From f805a76e792ca27392db5695b8ccd7902a6c02cc Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Wed, 13 Nov 2019 17:27:16 +0530 Subject: [PATCH 001/137] chore: pinned requirements --- requirements.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/requirements.txt b/requirements.txt index 28ba9f676ff..429f894edce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ frappe -unidecode -pygithub -googlemaps -python-stdnum -braintree -gocardless_pro -woocommerce -pandas -plaid-python \ No newline at end of file +Unidecode==1.1.1 +PyGithub==1.43.8 +googlemaps==3.1.1 +python-stdnum==1.11 +braintree==3.57.1 +gocardless-pro==1.10.0 +WooCommerce==2.1.1 +pandas==0.25.1 +plaid-python==3.4.0 From 3798f8bd25d6ac02c7d09da61e45db8c9a5c51e4 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 15 Nov 2019 13:59:15 +0530 Subject: [PATCH 002/137] style(requirements): alphabetically sorted requirements --- requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index 429f894edce..1ab84ad57b5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ -frappe -Unidecode==1.1.1 -PyGithub==1.43.8 -googlemaps==3.1.1 -python-stdnum==1.11 braintree==3.57.1 +frappe gocardless-pro==1.10.0 -WooCommerce==2.1.1 +googlemaps==3.1.1 pandas==0.25.1 plaid-python==3.4.0 +PyGithub==1.43.8 +python-stdnum==1.11 +Unidecode==1.1.1 +WooCommerce==2.1.1 From 73089470b18f2a04a28b3ba3391b1605e12becf4 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 15 Nov 2019 17:38:32 +0530 Subject: [PATCH 003/137] chore: pinned backwards compatible dependencies --- requirements.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 1ab84ad57b5..c277545fab5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ braintree==3.57.1 frappe -gocardless-pro==1.10.0 +gocardless-pro==1.11.0 googlemaps==3.1.1 -pandas==0.25.1 +pandas==0.24.2 plaid-python==3.4.0 -PyGithub==1.43.8 -python-stdnum==1.11 +PyGithub==1.44.1 +python-stdnum==1.12 Unidecode==1.1.1 WooCommerce==2.1.1 From 637915f295d4879e90ef30cbc6b9ab12820ae5af Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 28 Jan 2020 13:11:49 +0530 Subject: [PATCH 004/137] fix: odometer value was not syncing properly --- erpnext/hr/doctype/vehicle_log/vehicle_log.js | 38 +- .../hr/doctype/vehicle_log/vehicle_log.json | 842 ++++-------------- erpnext/hr/doctype/vehicle_log/vehicle_log.py | 18 +- 3 files changed, 201 insertions(+), 697 deletions(-) diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.js b/erpnext/hr/doctype/vehicle_log/vehicle_log.js index 7694cfed7cc..4c192a0234b 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.js +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.js @@ -2,19 +2,10 @@ // For license information, please see license.txt frappe.ui.form.on("Vehicle Log", { - refresh: function(frm,cdt,cdn) { - var vehicle_log=frappe.model.get_doc(cdt,cdn); - if (vehicle_log.license_plate) { - frappe.call({ - method: "erpnext.hr.doctype.vehicle_log.vehicle_log.get_make_model", - args: { - license_plate: vehicle_log.license_plate - }, - callback: function(r) { - frappe.model.set_value(cdt, cdn, ("model"), r.message[0]); - frappe.model.set_value(cdt, cdn, ("make"), r.message[1]); - } - }) + refresh: function(frm) { + + if(frm.doc.license_plate && frm.doc.__islocal){ + frm.events.set_vehicle_details(frm) } if(frm.doc.docstatus == 1) { @@ -25,6 +16,27 @@ frappe.ui.form.on("Vehicle Log", { } }, + license_plate: function(frm){ + if(frm.doc.license_plate){ + frm.events.set_vehicle_details(frm) + } + }, + + set_vehicle_details: function(frm){ + frappe.call({ + method: "erpnext.hr.doctype.vehicle_log.vehicle_log.get_make_model", + args: { + license_plate: frm.doc.license_plate + }, + callback: function(r) { + frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "model", r.message[0]); + frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "make", r.message[1]); + frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "last_odometer", r.message[2]); + frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "employee", r.message[3]); + } + }); + }, + expense_claim: function(frm){ frappe.call({ method: "erpnext.hr.doctype.vehicle_log.vehicle_log.make_expense_claim", diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.json b/erpnext/hr/doctype/vehicle_log/vehicle_log.json index cde39e7ee44..52effffc064 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.json +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.json @@ -1,706 +1,192 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 0, - "creation": "2016-09-03 14:14:51.788550", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, + "actions": [], + "autoname": "naming_series:", + "creation": "2016-09-03 14:14:51.788550", + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "vehicle_section", + "naming_series", + "license_plate", + "employee", + "column_break_4", + "column_break_7", + "model", + "make", + "odometer_reading", + "date", + "odometer", + "column_break_12", + "last_odometer", + "refuelling_details", + "fuel_qty", + "price", + "column_break_15", + "supplier", + "invoice", + "service_details", + "service_detail", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "vehicle_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "options": "fa fa-user", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "vehicle_section", + "fieldtype": "Section Break", + "options": "fa fa-user" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 1, - "options": "HR-VLOG-.YYYY.-", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "options": "HR-VLOG-.YYYY.-", + "print_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "license_plate", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "License Plate", - "length": 0, - "no_copy": 0, - "options": "Vehicle", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "license_plate", + "fieldtype": "Link", + "in_global_search": 1, + "in_list_view": 1, + "label": "License Plate", + "options": "Vehicle", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "employee", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Employee", - "length": 0, - "no_copy": 0, - "options": "Employee", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "employee", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Employee", + "options": "Employee", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_4", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_7", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_7", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "model", - "fieldtype": "Read Only", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Model", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "model", + "fieldtype": "Read Only", + "label": "Model" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "make", - "fieldtype": "Read Only", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Make", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "make", + "fieldtype": "Read Only", + "label": "Make" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "odometer_reading", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Odometer Reading", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "odometer_reading", + "fieldtype": "Section Break", + "label": "Odometer Reading" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "date", + "fieldtype": "Date", + "label": "Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "odometer", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Odometer", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "odometer", + "fieldtype": "Int", + "label": "Current Odometer value ", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "refuelling_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Refuelling Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "refuelling_details", + "fieldtype": "Section Break", + "label": "Refuelling Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "fuel_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Fuel Qty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "fuel_qty", + "fieldtype": "Float", + "label": "Fuel Qty" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "price", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Fuel Price", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "price", + "fieldtype": "Currency", + "label": "Fuel Price" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_15", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_15", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "supplier", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplier", - "length": 0, - "no_copy": 0, - "options": "Supplier", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "supplier", + "fieldtype": "Link", + "label": "Supplier", + "options": "Supplier" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "invoice", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Invoice Ref", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "invoice", + "fieldtype": "Data", + "label": "Invoice Ref" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "service_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Service Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "service_details", + "fieldtype": "Section Break", + "label": "Service Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "service_detail", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Service Detail", - "length": 0, - "no_copy": 0, - "options": "Vehicle Service", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "service_detail", + "fieldtype": "Table", + "label": "Service Detail", + "options": "Vehicle Service" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amended From", - "length": 0, - "no_copy": 1, - "options": "Vehicle Log", - "permlevel": 0, - "print_hide": 1, - "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 + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Vehicle Log", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "last_odometer", + "fieldtype": "Int", + "label": "last Odometer Value ", + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "column_break_12", + "fieldtype": "Column Break" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-21 14:44:51.131186", - "modified_by": "Administrator", - "module": "HR", - "name": "Vehicle Log", - "name_case": "", - "owner": "Administrator", + ], + "is_submittable": 1, + "links": [], + "modified": "2020-01-28 12:43:34.419647", + "modified_by": "Administrator", + "module": "HR", + "name": "Vehicle Log", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Fleet Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Fleet Manager", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.py b/erpnext/hr/doctype/vehicle_log/vehicle_log.py index df633611be8..0dbf1ceb961 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.py @@ -11,22 +11,28 @@ from frappe.model.document import Document class VehicleLog(Document): def validate(self): - last_odometer=frappe.db.get_value("Vehicle", self.license_plate, "last_odometer") - if flt(self.odometer) < flt(last_odometer): - frappe.throw(_("Current Odometer reading entered should be greater than initial Vehicle Odometer {0}").format(last_odometer)) + if flt(self.odometer) < flt(self.last_odometer): + frappe.throw(_("Current Odometer reading entered should be greater than initial Vehicle Odometer {0}").format(self.last_odometer)) for service_detail in self.service_detail: if (service_detail.service_item or service_detail.type or service_detail.frequency or service_detail.expense_amount): if not (service_detail.service_item and service_detail.type and service_detail.frequency and service_detail.expense_amount): frappe.throw(_("Service Item,Type,frequency and expense amount are required")) def on_submit(self): - frappe.db.sql("update `tabVehicle` set last_odometer=%s where license_plate=%s", - (self.odometer, self.license_plate)) + print("I am here") + frappe.db.set_value("Vehicle", self.license_plate, "last_odometer", self.odometer) + + def on_cancel(self): + print("sel"*10, self.last_odometer, self.odometer) + distance_travelled = self.odometer - self.last_odometer + if(distance_travelled > 0): + updated_odometer_value = int(frappe.db.get_value("Vehicle", self.license_plate, "last_odometer")) - distance_travelled + frappe.db.set_value("Vehicle", self.license_plate, "last_odometer", updated_odometer_value) @frappe.whitelist() def get_make_model(license_plate): vehicle=frappe.get_doc("Vehicle",license_plate) - return (vehicle.make,vehicle.model) + return (vehicle.make,vehicle.model,vehicle.last_odometer,vehicle.employee) @frappe.whitelist() def make_expense_claim(docname): From a175e06149b130dce7433a95c532d98e4d59d3f6 Mon Sep 17 00:00:00 2001 From: racitup Date: Mon, 20 Jan 2020 18:56:35 +0000 Subject: [PATCH 005/137] fix: pymysql.err.InternalError about t2.bank_account_no due to removal of field from Journal Entry Account table: #20343 --- .../doctype/bank_reconciliation/bank_reconciliation.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 90cdf834c59..3613a1ef696 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -21,10 +21,6 @@ class BankReconciliation(Document): if not self.include_reconciled_entries: condition = " and (clearance_date is null or clearance_date='0000-00-00')" - account_cond = "" - if self.bank_account_no: - account_cond = " and t2.bank_account_no = {0}".format(frappe.db.escape(self.bank_account_no)) - journal_entries = frappe.db.sql(""" select "Journal Entry" as payment_document, t1.name as payment_entry, @@ -36,10 +32,10 @@ class BankReconciliation(Document): where t2.parent = t1.name and t2.account = %s and t1.docstatus=1 and t1.posting_date >= %s and t1.posting_date <= %s - and ifnull(t1.is_opening, 'No') = 'No' {0} {1} + and ifnull(t1.is_opening, 'No') = 'No' {0} group by t2.account, t1.name order by t1.posting_date ASC, t1.name DESC - """.format(condition, account_cond), (self.bank_account, self.from_date, self.to_date), as_dict=1) + """.format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1) if self.bank_account_no: condition = " and bank_account = %(bank_account_no)s" From feaa82a8eab5b5c415cdbff718b6eb64b1aaf9d6 Mon Sep 17 00:00:00 2001 From: racitup Date: Mon, 20 Jan 2020 19:41:08 +0000 Subject: [PATCH 006/137] fix: KeyError about bank_account_no due to non-existent field: #20343 --- .../doctype/bank_reconciliation/bank_reconciliation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 3613a1ef696..d5ba49abd0f 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -68,11 +68,10 @@ class BankReconciliation(Document): from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account where sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name - and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s {0} + and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s order by si.posting_date ASC, si.name DESC - """.format(condition), - {"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1) + """, {"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1) entries = sorted(list(payment_entries)+list(journal_entries+list(pos_entries)), key=lambda k: k['posting_date'] or getdate(nowdate())) From a05450821182bce276f1242761b5b2a670b03663 Mon Sep 17 00:00:00 2001 From: racitup Date: Tue, 21 Jan 2020 00:47:10 +0000 Subject: [PATCH 007/137] fix: Plaid automatic_synchronization TypeError on filter & add info log message #20343 --- .../doctype/plaid_settings/plaid_settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py index a04d6c5be73..9e22dc07bb6 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py @@ -133,8 +133,11 @@ def sync_transactions(bank, bank_account): try: transactions = get_transactions(bank=bank, bank_account=bank_account, start_date=start_date, end_date=end_date) + result = [] if transactions: + frappe.logger().info("Plaid is adding {} Bank Transactions from '{}' between {} and {}".format( + len(transactions), bank_account, start_date, end_date)) for transaction in transactions: result.append(new_bank_transaction(transaction)) @@ -201,7 +204,7 @@ def automatic_synchronization(): settings = frappe.get_doc("Plaid Settings", "Plaid Settings") if settings.enabled == 1 and settings.automatic_sync == 1: - plaid_accounts = frappe.get_all("Bank Account", filter={"integration_id": ["!=", ""]}, fields=["name", "bank"]) + plaid_accounts = frappe.get_all("Bank Account", filters={"integration_id": ["!=", ""]}, fields=["name", "bank"]) for plaid_account in plaid_accounts: frappe.enqueue("erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions", bank=plaid_account.bank, bank_account=plaid_account.name) From bee017e17c78aed52dee5ebf4f92fa4184dfa08e Mon Sep 17 00:00:00 2001 From: racitup Date: Tue, 21 Jan 2020 15:07:47 +0000 Subject: [PATCH 008/137] fix: Plaid transaction import order, transaction_id duplicate check, added transaction category tags --- .../doctype/plaid_settings/plaid_settings.py | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py index 9e22dc07bb6..970793f7468 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py @@ -10,6 +10,7 @@ from frappe.model.document import Document from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_connector import PlaidConnector from frappe.utils import getdate, formatdate, today, add_months +from frappe.desk.doctype.tag.tag import add_tag class PlaidSettings(Document): pass @@ -135,11 +136,11 @@ def sync_transactions(bank, bank_account): transactions = get_transactions(bank=bank, bank_account=bank_account, start_date=start_date, end_date=end_date) result = [] - if transactions: - frappe.logger().info("Plaid is adding {} Bank Transactions from '{}' between {} and {}".format( - len(transactions), bank_account, start_date, end_date)) - for transaction in transactions: - result.append(new_bank_transaction(transaction)) + for transaction in reversed(transactions): + result += new_bank_transaction(transaction) + + frappe.logger().info("Plaid added {} new Bank Transactions from '{}' between {} and {}".format( + len(result), bank_account, start_date, end_date)) frappe.db.set_value("Bank Account", bank_account, "last_integration_date", getdate(end_date)) @@ -178,6 +179,13 @@ def new_bank_transaction(transaction): status = "Pending" if transaction["pending"] == "True" else "Settled" + try: + tags = [] + tags += transaction["category"] + tags += ["Plaid Cat. {}".format(transaction["category_id"])] + except KeyError: + pass + if not frappe.db.exists("Bank Transaction", dict(transaction_id=transaction["transaction_id"])): try: new_transaction = frappe.get_doc({ @@ -188,11 +196,16 @@ def new_bank_transaction(transaction): "debit": debit, "credit": credit, "currency": transaction["iso_currency_code"], + "transaction_id": transaction["transaction_id"], + "reference_number": transaction["payment_meta"]["reference_number"], "description": transaction["name"] }) new_transaction.insert() new_transaction.submit() + for tag in tags: + add_tag(tag, "Bank Transaction", new_transaction.name) + result.append(new_transaction.name) except Exception: From a1e3202054235d7b7ab30ec3b3b3cb78eabf86b0 Mon Sep 17 00:00:00 2001 From: racitup Date: Wed, 22 Jan 2020 04:32:15 +0000 Subject: [PATCH 009/137] fix: Bank Reconciliation Bank Account and Bank Account No field names --- .../bank_reconciliation.js | 6 +++--- .../bank_reconciliation.json | 18 +++++++--------- .../bank_reconciliation.py | 21 ++++++++----------- .../rename_bank_reconciliation_fields.py | 16 ++++++++++++++ 4 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 erpnext/patches/v12_0/rename_bank_reconciliation_fields.py diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js index 7c94455b9ba..19fadbf6ded 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js @@ -3,16 +3,16 @@ frappe.ui.form.on("Bank Reconciliation", { setup: function(frm) { - frm.add_fetch("bank_account", "account_currency", "account_currency"); + frm.add_fetch("account", "account_currency", "account_currency"); }, onload: function(frm) { let default_bank_account = frappe.defaults.get_user_default("Company")? locals[":Company"][frappe.defaults.get_user_default("Company")]["default_bank_account"]: ""; - frm.set_value("bank_account", default_bank_account); + frm.set_value("account", default_bank_account); - frm.set_query("bank_account", function() { + frm.set_query("account", function() { return { "filters": { "account_type": ["in",["Bank","Cash"]], diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.json b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.json index e2f967daccb..b85ef3e9c4d 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.json +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.json @@ -19,10 +19,9 @@ "bold": 0, "collapsible": 0, "columns": 0, - "description": "Select account head of the bank where cheque was deposited.", - "fetch_from": "bank_account_no.account", + "fetch_from": "bank_account.account", "fetch_if_empty": 1, - "fieldname": "bank_account", + "fieldname": "account", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -31,7 +30,7 @@ "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 0, - "label": "Bank Account", + "label": "Account", "length": 0, "no_copy": 0, "options": "Account", @@ -164,7 +163,6 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -183,8 +181,9 @@ "bold": 0, "collapsible": 0, "columns": 0, + "description": "Select the Bank Account to reconcile.", "fetch_if_empty": 0, - "fieldname": "bank_account_no", + "fieldname": "bank_account", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -193,12 +192,11 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Bank Account No", + "label": "Bank Account", "length": 0, "no_copy": 0, "options": "Bank Account", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -450,7 +448,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2019-04-09 18:41:06.110453", + "modified": "2020-01-22 00:00:00.000000", "modified_by": "Administrator", "module": "Accounts", "name": "Bank Reconciliation", @@ -483,4 +481,4 @@ "track_changes": 0, "track_seen": 0, "track_views": 0 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index d5ba49abd0f..804bcd8bdf0 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -30,15 +30,12 @@ class BankReconciliation(Document): from `tabJournal Entry` t1, `tabJournal Entry Account` t2 where - t2.parent = t1.name and t2.account = %s and t1.docstatus=1 - and t1.posting_date >= %s and t1.posting_date <= %s - and ifnull(t1.is_opening, 'No') = 'No' {0} + t2.parent = t1.name and t2.account = %(account)s and t1.docstatus=1 + and t1.posting_date >= %(from)s and t1.posting_date <= %(to)s + and ifnull(t1.is_opening, 'No') = 'No' %(condition)s group by t2.account, t1.name order by t1.posting_date ASC, t1.name DESC - """.format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1) - - if self.bank_account_no: - condition = " and bank_account = %(bank_account_no)s" + """, {"condition":condition, "account":self.account, "from":self.from_date, "to":self.to_date}, as_dict=1) payment_entries = frappe.db.sql(""" select @@ -51,12 +48,12 @@ class BankReconciliation(Document): from `tabPayment Entry` where (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1 - and posting_date >= %(from)s and posting_date <= %(to)s {0} + and posting_date >= %(from)s and posting_date <= %(to)s + and bank_account = %(bank_account)s order by posting_date ASC, name DESC - """.format(condition), - {"account":self.bank_account, "from":self.from_date, - "to":self.to_date, "bank_account_no": self.bank_account_no}, as_dict=1) + """, {"account":self.account, "from":self.from_date, + "to":self.to_date, "bank_account": self.bank_account}, as_dict=1) pos_entries = [] if self.include_pos_transactions: @@ -71,7 +68,7 @@ class BankReconciliation(Document): and account.name = sip.account and si.posting_date >= %(from)s and si.posting_date <= %(to)s order by si.posting_date ASC, si.name DESC - """, {"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1) + """, {"account":self.account, "from":self.from_date, "to":self.to_date}, as_dict=1) entries = sorted(list(payment_entries)+list(journal_entries+list(pos_entries)), key=lambda k: k['posting_date'] or getdate(nowdate())) diff --git a/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py b/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py new file mode 100644 index 00000000000..8918b9df7a0 --- /dev/null +++ b/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py @@ -0,0 +1,16 @@ +import frappe + +def _rename_single_field(**kwargs): + count = frappe.db.sql("SELECT COUNT(*) FROM tabSingles WHERE doctype='{doctype}' AND field='{new_name}';".format(**kwargs))[0][0] + if count == 0: + frappe.db.sql("UPDATE tabSingles SET field='{new_name}' WHERE doctype='{doctype}' AND field='{old_name}';".format(**kwargs)) + +def execute(): + BR = "Bank Reconciliation" + AC = "account" + BA = "bank_account" + BAN = "bank_account_no" + + _rename_single_field(doctype = BR, old_name = BA , new_name = AC) + _rename_single_field(doctype = BR, old_name = BAN, new_name = BA) + frappe.reload_doc("Accounts", "doctype", BR) From eef73a0d920598f5722ae324aed18a274b23be47 Mon Sep 17 00:00:00 2001 From: racitup Date: Fri, 24 Jan 2020 23:40:16 +0000 Subject: [PATCH 010/137] manually added patch for bank reconciliation fields since develop branch was in a different place #20380 --- erpnext/patches.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 17c9a20766d..bbb875a3191 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -648,3 +648,4 @@ erpnext.patches.v12_0.update_owner_fields_in_acc_dimension_custom_fields erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger erpnext.patches.v12_0.update_price_or_product_discount erpnext.patches.v12_0.add_export_type_field_in_party_master +erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22 From 814001a90fcf84e910136cfead34973cdef434e5 Mon Sep 17 00:00:00 2001 From: racitup Date: Wed, 22 Jan 2020 04:41:41 +0000 Subject: [PATCH 011/137] fix: attempt at pymysql InternalError 1054 about clearance_date in field list when removing payments from bank transactions --- .../bank_transaction_payments.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.json b/erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.json index a75e866997d..ab3f60d32c0 100644 --- a/erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.json +++ b/erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.json @@ -110,6 +110,15 @@ "set_only_once": 0, "translatable": 0, "unique": 0 + }, + { + "depends_on": "eval:doc.docstatus==1", + "fieldname": "clearance_date", + "fieldtype": "Date", + "label": "Clearance Date", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 } ], "has_web_view": 0, @@ -122,7 +131,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-12-06 10:57:02.635141", + "modified": "2020-01-22 00:00:00.000000", "modified_by": "Administrator", "module": "Accounts", "name": "Bank Transaction Payments", @@ -138,4 +147,4 @@ "track_changes": 1, "track_seen": 0, "track_views": 0 -} \ No newline at end of file +} From 08661250d231f07a5068db3903a6bb16134c5eed Mon Sep 17 00:00:00 2001 From: racitup Date: Thu, 30 Jan 2020 14:48:42 +0000 Subject: [PATCH 012/137] Ignore codacy SQL injection warning (internal code only) and add copyright notice --- erpnext/patches/v12_0/rename_bank_reconciliation_fields.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py b/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py index 8918b9df7a0..01b1dde6073 100644 --- a/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py +++ b/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py @@ -1,9 +1,12 @@ +# Copyright (c) 2020, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + import frappe def _rename_single_field(**kwargs): - count = frappe.db.sql("SELECT COUNT(*) FROM tabSingles WHERE doctype='{doctype}' AND field='{new_name}';".format(**kwargs))[0][0] + count = frappe.db.sql("SELECT COUNT(*) FROM tabSingles WHERE doctype='{doctype}' AND field='{new_name}';".format(**kwargs))[0][0] #nosec if count == 0: - frappe.db.sql("UPDATE tabSingles SET field='{new_name}' WHERE doctype='{doctype}' AND field='{old_name}';".format(**kwargs)) + frappe.db.sql("UPDATE tabSingles SET field='{new_name}' WHERE doctype='{doctype}' AND field='{old_name}';".format(**kwargs)) #nosec def execute(): BR = "Bank Reconciliation" From ce598530dbf04ac0fb51b46a9d508e0ad2c30c5c Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 5 Feb 2020 12:45:43 +0530 Subject: [PATCH 013/137] fix: requested changes --- erpnext/hr/doctype/vehicle_log/vehicle_log.js | 14 +++++++------- erpnext/hr/doctype/vehicle_log/vehicle_log.py | 11 ++++++++--- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.js b/erpnext/hr/doctype/vehicle_log/vehicle_log.js index 4c192a0234b..bdb37d2b734 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.js +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.js @@ -5,32 +5,32 @@ frappe.ui.form.on("Vehicle Log", { refresh: function(frm) { if(frm.doc.license_plate && frm.doc.__islocal){ - frm.events.set_vehicle_details(frm) + frm.events.set_vehicle_details(frm); } if(frm.doc.docstatus == 1) { frm.add_custom_button(__('Expense Claim'), function() { - frm.events.expense_claim(frm) + frm.events.expense_claim(frm); }, __('Create')); frm.page.set_inner_btn_group_as_primary(__('Create')); } }, - license_plate: function(frm){ + license_plate: function(frm) { if(frm.doc.license_plate){ - frm.events.set_vehicle_details(frm) + frm.events.set_vehicle_details(frm); } }, - set_vehicle_details: function(frm){ + set_vehicle_details: function(frm) { frappe.call({ method: "erpnext.hr.doctype.vehicle_log.vehicle_log.get_make_model", args: { license_plate: frm.doc.license_plate }, callback: function(r) { - frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "model", r.message[0]); - frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "make", r.message[1]); + frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "make", r.message[0]); + frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "model", r.message[1]); frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "last_odometer", r.message[2]); frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "employee", r.message[3]); } diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.py b/erpnext/hr/doctype/vehicle_log/vehicle_log.py index 0dbf1ceb961..dfdfc0d7202 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.py @@ -18,12 +18,17 @@ class VehicleLog(Document): if not (service_detail.service_item and service_detail.type and service_detail.frequency and service_detail.expense_amount): frappe.throw(_("Service Item,Type,frequency and expense amount are required")) + def before_save(self): + model_details = get_make_model(self.license_plate) + self.make = model_details[0] + self.model = model_details[1] + self.last_odometer = model_details[2] + self.employee = model_details[3] + def on_submit(self): - print("I am here") frappe.db.set_value("Vehicle", self.license_plate, "last_odometer", self.odometer) def on_cancel(self): - print("sel"*10, self.last_odometer, self.odometer) distance_travelled = self.odometer - self.last_odometer if(distance_travelled > 0): updated_odometer_value = int(frappe.db.get_value("Vehicle", self.license_plate, "last_odometer")) - distance_travelled @@ -32,7 +37,7 @@ class VehicleLog(Document): @frappe.whitelist() def get_make_model(license_plate): vehicle=frappe.get_doc("Vehicle",license_plate) - return (vehicle.make,vehicle.model,vehicle.last_odometer,vehicle.employee) + return (vehicle.make, vehicle.model, vehicle.last_odometer, vehicle.employee) @frappe.whitelist() def make_expense_claim(docname): From f5bff5f15d69b44ec86c8c39f539eb3e0c2dd055 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 7 Feb 2020 15:25:43 +0530 Subject: [PATCH 014/137] fix: Styling and minor fixes --- .../bank_reconciliation/bank_reconciliation.py | 6 +++--- .../doctype/plaid_settings/plaid_settings.json | 7 ++++--- .../v12_0/rename_bank_reconciliation_fields.py | 11 +++-------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 804bcd8bdf0..52bbe3327a8 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -35,7 +35,7 @@ class BankReconciliation(Document): and ifnull(t1.is_opening, 'No') = 'No' %(condition)s group by t2.account, t1.name order by t1.posting_date ASC, t1.name DESC - """, {"condition":condition, "account":self.account, "from":self.from_date, "to":self.to_date}, as_dict=1) + """, {"condition":condition, "account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1) payment_entries = frappe.db.sql(""" select @@ -52,8 +52,8 @@ class BankReconciliation(Document): and bank_account = %(bank_account)s order by posting_date ASC, name DESC - """, {"account":self.account, "from":self.from_date, - "to":self.to_date, "bank_account": self.bank_account}, as_dict=1) + """, {"account": self.account, "from":self.from_date, + "to": self.to_date, "bank_account": self.bank_account}, as_dict=1) pos_entries = [] if self.include_pos_transactions: diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json index df77ad8bc93..d8203d7390f 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json @@ -49,9 +49,10 @@ }, { "fieldname": "plaid_env", - "fieldtype": "Data", + "fieldtype": "Select", "in_list_view": 1, - "label": "Plaid Environment" + "label": "Plaid Environment", + "options": "sandbox\ndevelopment\nproduction" }, { "fieldname": "column_break_2", @@ -69,7 +70,7 @@ ], "issingle": 1, "links": [], - "modified": "2020-01-05 10:00:22.137832", + "modified": "2020-02-07 15:21:11.616231", "modified_by": "Administrator", "module": "ERPNext Integrations", "name": "Plaid Settings", diff --git a/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py b/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py index 01b1dde6073..caeda8ae61b 100644 --- a/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py +++ b/erpnext/patches/v12_0/rename_bank_reconciliation_fields.py @@ -9,11 +9,6 @@ def _rename_single_field(**kwargs): frappe.db.sql("UPDATE tabSingles SET field='{new_name}' WHERE doctype='{doctype}' AND field='{old_name}';".format(**kwargs)) #nosec def execute(): - BR = "Bank Reconciliation" - AC = "account" - BA = "bank_account" - BAN = "bank_account_no" - - _rename_single_field(doctype = BR, old_name = BA , new_name = AC) - _rename_single_field(doctype = BR, old_name = BAN, new_name = BA) - frappe.reload_doc("Accounts", "doctype", BR) + _rename_single_field(doctype = "Bank Reconciliation", old_name = "bank_account" , new_name = "account") + _rename_single_field(doctype = "Bank Reconciliation", old_name = "bank_account_no", new_name = "bank_account") + frappe.reload_doc("Accounts", "doctype", "Bank Reconciliation") From fc4cc9ab42ae36c5e705517e4f327b528dd471c5 Mon Sep 17 00:00:00 2001 From: Er-Naren719 <49683121+Er-Naren719@users.noreply.github.com> Date: Mon, 10 Feb 2020 13:46:47 +0530 Subject: [PATCH 015/137] feat: column width increased for view attachments field (#314) --- erpnext/projects/doctype/project_user/project_user.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/erpnext/projects/doctype/project_user/project_user.json b/erpnext/projects/doctype/project_user/project_user.json index f0a70dd1df9..2f452cc2d75 100644 --- a/erpnext/projects/doctype/project_user/project_user.json +++ b/erpnext/projects/doctype/project_user/project_user.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2016-03-25 02:52:19.283003", "doctype": "DocType", "editable_grid": 1, @@ -46,6 +47,7 @@ "fetch_from": "user.full_name", "fieldname": "full_name", "fieldtype": "Read Only", + "in_list_view": 1, "label": "Full Name" }, { @@ -55,7 +57,7 @@ "label": "Welcome email sent" }, { - "columns": 1, + "columns": 2, "default": "0", "fieldname": "view_attachments", "fieldtype": "Check", @@ -74,7 +76,8 @@ } ], "istable": 1, - "modified": "2019-07-15 19:37:26.942294", + "links": [], + "modified": "2020-02-09 23:26:50.321417", "modified_by": "Administrator", "module": "Projects", "name": "Project User", From efbfeb2d89830c32720e3fd3feb1c2707046e862 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 17 Feb 2020 10:50:05 +0530 Subject: [PATCH 016/137] fix: filters for quality_procedure tree --- .../doctype/quality_procedure/quality_procedure_tree.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js index dbdbbab3925..6df6f656aa1 100644 --- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js +++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure_tree.js @@ -4,7 +4,7 @@ frappe.treeview_settings["Quality Procedure"] = { add_tree_node: 'erpnext.quality_management.doctype.quality_procedure.quality_procedure.add_node', filters: [ { - fieldname: "quality_procedure", + fieldname: "parent_quality_procedure", fieldtype: "Link", options: "Quality Procedure", label: __("Quality Procedure"), From 5bfebaf1c0417141340c12f8a9f7a78139e42617 Mon Sep 17 00:00:00 2001 From: thefalconx33 Date: Mon, 17 Feb 2020 14:15:20 +0530 Subject: [PATCH 017/137] fix: disabled mode of payments fetches in sales invoices --- .../doctype/mode_of_payment/mode_of_payment.py | 13 +++++++++++++ erpnext/accounts/doctype/sales_invoice/pos.py | 7 +++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py index fcf94ce98a9..d54a47e3c96 100644 --- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py +++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py @@ -11,6 +11,7 @@ class ModeofPayment(Document): def validate(self): self.validate_accounts() self.validate_repeating_companies() + self.validate_pos_mode_of_payment() def validate_repeating_companies(self): """Error when Same Company is entered multiple times in accounts""" @@ -27,3 +28,15 @@ class ModeofPayment(Document): if frappe.db.get_value("Account", entry.default_account, "company") != entry.company: frappe.throw(_("Account {0} does not match with Company {1} in Mode of Account: {2}") .format(entry.default_account, entry.company, self.name)) + + def validate_pos_mode_of_payment(self): + if not self.enabled: + pos_profiles = frappe.db.sql("""SELECT sip.parent FROM `tabSales Invoice Payment` sip + WHERE sip.parenttype = 'POS Profile' and sip.mode_of_payment = %s""", (self.name)) + pos_profiles = list(map(lambda x: x[0], pos_profiles)) + + if pos_profiles: + message = "POS Profile " + frappe.bold(", ".join(pos_profiles)) + " contains \ + Mode of Payment " + frappe.bold(str(self.name)) + ". Please remove them to disable this mode." + frappe.throw(_(message), title="Not Allowed") + diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index a48d2244893..749816f7814 100755 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -152,8 +152,11 @@ def update_multi_mode_option(doc, pos_profile): def get_mode_of_payment(doc): - return frappe.db.sql(""" select mpa.default_account, mpa.parent, mp.type as type from `tabMode of Payment Account` mpa, \ - `tabMode of Payment` mp where mpa.parent = mp.name and mpa.company = %(company)s""", {'company': doc.company}, as_dict=1) + return frappe.db.sql(""" + select mpa.default_account, mpa.parent, mp.type as type + from `tabMode of Payment Account` mpa,`tabMode of Payment` mp + where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""", + {'company': doc.company}, as_dict=1) def update_tax_table(doc): From 660b4d1e2fbef983e99bf4ad5710412b98ac0f02 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 17 Feb 2020 15:58:31 +0530 Subject: [PATCH 018/137] feat: show numeric values in item configurator (#20430) --- erpnext/portal/product_configurator/utils.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py index 336b9319c1d..ce507a39486 100644 --- a/erpnext/portal/product_configurator/utils.py +++ b/erpnext/portal/product_configurator/utils.py @@ -1,4 +1,5 @@ import frappe +import numpy as np from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager def get_field_filter_data(): @@ -172,6 +173,7 @@ def get_attributes_and_values(item_code): item_attribute_values = frappe.db.get_all('Item Attribute Value', ['parent', 'attribute_value', 'idx'], order_by='parent asc, idx asc') + item_attribute_values += get_numeric_values() ordered_attribute_value_map = frappe._dict() for iv in item_attribute_values: ordered_attribute_value_map.setdefault(iv.parent, []).append(iv.attribute_value) @@ -184,6 +186,23 @@ def get_attributes_and_values(item_code): return attributes +def get_numeric_values(): + attribute_values_list = [] + numeric_attributes = frappe.get_list("Item Attribute", fields=['name', 'from_range', 'to_range', 'increment'], filters={"numeric_values": 1}) + for attribute in numeric_attributes: + from_range = attribute["from_range"] + to_range = attribute['to_range'] + attribute['increment'] + increment = attribute['increment'] + values = list(np.arange(from_range, to_range, increment)) + + for idx, val in enumerate(values): + attribute_values_list.append(frappe._dict({ + "parent": attribute.get("name"), + "attribute_value": str(int(val)) if val.is_integer() else str(val), + "idx": idx + })) + return attribute_values_list + @frappe.whitelist(allow_guest=True) def get_next_attribute_and_values(item_code, selected_attributes): From f95ac99baa6c60a270b3a4ff52fab3b957b6c12e Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Wed, 27 Nov 2019 14:53:58 +0530 Subject: [PATCH 019/137] fix(travis): add lib cups for updated frappe requirements --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 40afeee8d46..365eb67f3dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,6 +63,7 @@ install: - tar -xf /tmp/wkhtmltox.tar.xz -C /tmp - sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf - sudo chmod o+x /usr/local/bin/wkhtmltopdf + - sudo apt-get install libcups2-dev - cd ~/frappe-bench From 6f28383531a78bb452722f3e454b99c1807343b7 Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 18 Feb 2020 10:51:54 +0530 Subject: [PATCH 020/137] fix: Stock Quantity not calculated on client side in Material Request Items. --- erpnext/public/js/controllers/transaction.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 512bcf9f4fb..8c022e95fb5 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -941,15 +941,19 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }, conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) { - if(doc.doctype != 'Material Request' && frappe.meta.get_docfield(cdt, "stock_qty", cdn)) { + if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) { var item = frappe.get_doc(cdt, cdn); frappe.model.round_floats_in(item, ["qty", "conversion_factor"]); item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item)); - item.total_weight = flt(item.stock_qty * item.weight_per_unit); refresh_field("stock_qty", item.name, item.parentfield); - refresh_field("total_weight", item.name, item.parentfield); this.toggle_conversion_factor(item); - this.calculate_net_weight(); + + if(doc.doctype != "Material Request") { + item.total_weight = flt(item.stock_qty * item.weight_per_unit); + refresh_field("total_weight", item.name, item.parentfield); + this.calculate_net_weight(); + } + if (!dont_fetch_price_list_rate && frappe.meta.has_field(doc.doctype, "price_list_currency")) { this.apply_price_list(item, true); From b63c041aa429725de0251dd8878c58a2cd2dd8d7 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 18 Feb 2020 16:09:37 +0530 Subject: [PATCH 021/137] feat: Group by AR/AP report (#20574) * feat: Group by AR/AP report * fix: Do not consider total row in charts * fix: Subtotal row for last party --- .../accounts_payable/accounts_payable.js | 15 ++++ .../accounts_receivable.js | 16 +++- .../accounts_receivable.py | 75 ++++++++++++++++--- 3 files changed, 96 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js index b1f427ca7f6..df700ec9d3c 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.js +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js @@ -100,6 +100,11 @@ frappe.query_reports["Accounts Payable"] = { "fieldtype": "Link", "options": "Supplier Group" }, + { + "fieldname": "group_by_party", + "label": __("Group By Supplier"), + "fieldtype": "Check" + }, { "fieldname":"based_on_payment_terms", "label": __("Based On Payment Terms"), @@ -112,6 +117,16 @@ frappe.query_reports["Accounts Payable"] = { "hidden": 1 } ], + + "formatter": function(value, row, column, data, default_formatter) { + value = default_formatter(value, row, column, data); + if (data && data.bold) { + value = value.bold(); + + } + return value; + }, + onload: function(report) { report.page.add_inner_button(__("Accounts Payable Summary"), function() { var filters = report.get_values(); diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js index 9b4dda2f696..5d0154f597e 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js @@ -87,7 +87,7 @@ frappe.query_reports["Accounts Receivable"] = { frappe.query_report.set_filter_value('payment_terms', value["payment_terms"]); }); - frappe.db.get_value('Customer Credit Limit', {'parent': customer, 'company': company}, + frappe.db.get_value('Customer Credit Limit', {'parent': customer, 'company': company}, ["credit_limit"], function(value) { if (value) { frappe.query_report.set_filter_value('credit_limit', value["credit_limit"]); @@ -131,6 +131,11 @@ frappe.query_reports["Accounts Receivable"] = { "fieldtype": "Link", "options": "Sales Person" }, + { + "fieldname": "group_by_party", + "label": __("Group By Customer"), + "fieldtype": "Check" + }, { "fieldname":"based_on_payment_terms", "label": __("Based On Payment Terms"), @@ -177,6 +182,15 @@ frappe.query_reports["Accounts Receivable"] = { } ], + "formatter": function(value, row, column, data, default_formatter) { + value = default_formatter(value, row, column, data); + if (data && data.bold) { + value = value.bold(); + + } + return value; + }, + onload: function(report) { report.page.add_inner_button(__("Accounts Receivable Summary"), function() { var filters = report.get_values(); diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index f82146a1df8..0438f6d09e1 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -46,7 +46,7 @@ class ReceivablePayableReport(object): self.get_columns() self.get_data() self.get_chart_data() - return self.columns, self.data, None, self.chart + return self.columns, self.data, None, self.chart, None, self.skip_total_row def set_defaults(self): if not self.filters.get("company"): @@ -57,6 +57,12 @@ class ReceivablePayableReport(object): self.party_type = self.filters.party_type self.party_details = {} self.invoices = set() + self.skip_total_row = 0 + + if self.filters.get('group_by_party'): + self.previous_party='' + self.total_row_map = {} + self.skip_total_row = 1 def get_data(self): self.get_gl_entries() @@ -102,6 +108,12 @@ class ReceivablePayableReport(object): ) self.get_invoices(gle) + if self.filters.get('group_by_party'): + self.init_subtotal_row(gle.party) + + if self.filters.get('group_by_party'): + self.init_subtotal_row('Total') + def get_invoices(self, gle): if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'): if self.filters.get("sales_person"): @@ -111,6 +123,20 @@ class ReceivablePayableReport(object): else: self.invoices.add(gle.voucher_no) + def init_subtotal_row(self, party): + if not self.total_row_map.get(party): + self.total_row_map.setdefault(party, { + 'party': party, + 'bold': 1 + }) + + for field in self.get_currency_fields(): + self.total_row_map[party][field] = 0.0 + + def get_currency_fields(self): + return ['invoiced', 'paid', 'credit_note', 'outstanding', 'range1', + 'range2', 'range3', 'range4', 'range5'] + def update_voucher_balance(self, gle): # get the row where this balance needs to be updated # if its a payment, it will return the linked invoice or will be considered as advance @@ -135,6 +161,18 @@ class ReceivablePayableReport(object): # advance / unlinked payment or other adjustment row.paid -= gle_balance + def update_sub_total_row(self, row, party): + total_row = self.total_row_map.get(party) + + for field in self.get_currency_fields(): + total_row[field] += row.get(field, 0.0) + + def append_subtotal_row(self, party): + sub_total_row = self.total_row_map.get(party) + self.data.append(sub_total_row) + self.data.append({}) + self.update_sub_total_row(sub_total_row, 'Total') + def get_voucher_balance(self, gle): if self.filters.get("sales_person"): against_voucher = gle.against_voucher or gle.voucher_no @@ -192,11 +230,22 @@ class ReceivablePayableReport(object): else: self.append_row(row) + if self.filters.get('group_by_party'): + self.append_subtotal_row(self.previous_party) + self.data.append(self.total_row_map.get('Total')) + def append_row(self, row): self.allocate_future_payments(row) self.set_invoice_details(row) self.set_party_details(row) self.set_ageing(row) + + if self.filters.get('group_by_party'): + self.update_sub_total_row(row, row.party) + if self.previous_party and (self.previous_party != row.party): + self.append_subtotal_row(self.previous_party) + self.previous_party = row.party + self.data.append(row) def set_invoice_details(self, row): @@ -503,6 +552,7 @@ class ReceivablePayableReport(object): # get all the GL entries filtered by the given filters conditions, values = self.prepare_conditions() + order_by = self.get_order_by_condition() if self.filters.get(scrub(self.party_type)): select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit" @@ -520,9 +570,8 @@ class ReceivablePayableReport(object): and party_type=%s and (party is not null and party != '') and posting_date <= %s - {1} - order by posting_date, party""" - .format(select_fields, conditions), values, as_dict=True) + {1} {2}""" + .format(select_fields, conditions, order_by), values, as_dict=True) def get_sales_invoices_or_customers_based_on_sales_person(self): if self.filters.get("sales_person"): @@ -557,6 +606,12 @@ class ReceivablePayableReport(object): return " and ".join(conditions), values + def get_order_by_condition(self): + if self.filters.get('group_by_party'): + return "order by party, posting_date" + else: + return "order by posting_date, party" + def add_common_filters(self, conditions, values, party_type_field): if self.filters.company: conditions.append("company=%s") @@ -736,11 +791,13 @@ class ReceivablePayableReport(object): def get_chart_data(self): rows = [] for row in self.data: - values = [row.range1, row.range2, row.range3, row.range4, row.range5] - precision = cint(frappe.db.get_default("float_precision")) or 2 - rows.append({ - 'values': [flt(val, precision) for val in values] - }) + row = frappe._dict(row) + if not cint(row.bold): + values = [row.range1, row.range2, row.range3, row.range4, row.range5] + precision = cint(frappe.db.get_default("float_precision")) or 2 + rows.append({ + 'values': [flt(val, precision) for val in values] + }) self.chart = { "data": { From 1ed737cf6488389114abd833d6660b4178b1b101 Mon Sep 17 00:00:00 2001 From: marination Date: Tue, 18 Feb 2020 21:35:59 +0530 Subject: [PATCH 022/137] fix: Set Query on warehouse fields in Stock Settings --- erpnext/stock/doctype/stock_settings/stock_settings.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.js b/erpnext/stock/doctype/stock_settings/stock_settings.js index 49ce3d8ef7a..755c4307187 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.js +++ b/erpnext/stock/doctype/stock_settings/stock_settings.js @@ -3,6 +3,15 @@ frappe.ui.form.on('Stock Settings', { refresh: function(frm) { + let filters = function() { + return { + filters : { + is_group : 0 + } + }; + } + frm.set_query("default_warehouse", filters); + frm.set_query("sample_retention_warehouse", filters); } }); From 0119d15adb491d87dc8739c4cfa7a39c3e4caafe Mon Sep 17 00:00:00 2001 From: marination Date: Wed, 19 Feb 2020 11:05:58 +0530 Subject: [PATCH 023/137] fix: Server side validation for Warehouses --- erpnext/stock/doctype/stock_settings/stock_settings.js | 6 +++--- erpnext/stock/doctype/stock_settings/stock_settings.py | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.js b/erpnext/stock/doctype/stock_settings/stock_settings.js index 755c4307187..cc0e2cfc425 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.js +++ b/erpnext/stock/doctype/stock_settings/stock_settings.js @@ -5,11 +5,11 @@ frappe.ui.form.on('Stock Settings', { refresh: function(frm) { let filters = function() { return { - filters : { + filters : { is_group : 0 - } + } }; - } + }; frm.set_query("default_warehouse", filters); frm.set_query("sample_retention_warehouse", filters); diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py index 65de2e58d3a..93b5eee75c2 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.py +++ b/erpnext/stock/doctype/stock_settings/stock_settings.py @@ -30,9 +30,17 @@ class StockSettings(Document): frappe.make_property_setter({'fieldname': name, 'property': 'hidden', 'value': 0 if self.show_barcode_field else 1}) + self.validate_warehouses() self.cant_change_valuation_method() self.validate_clean_description_html() + def validate_warehouses(self): + warehouse_fields = ["default_warehouse", "sample_retention_warehouse"] + for field in warehouse_fields: + if frappe.db.get_value("Warehouse", self.get(field), "is_group"): + frappe.throw(_("Group Warehouses cannot be used in transactions. Please change the value of {0}") \ + .format(frappe.bold(self.meta.get_field(field).label)), title =_("Incorrect Warehouse")) + def cant_change_valuation_method(self): db_valuation_method = frappe.db.get_single_value("Stock Settings", "valuation_method") From 031d4092d0e20e4567b56a2b69283bb6ea0630a5 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 19 Feb 2020 16:46:00 +0530 Subject: [PATCH 024/137] test: syncing of odometer value --- .../doctype/vehicle_log/test_vehicle_log.py | 60 ++++++++++++------- erpnext/hr/doctype/vehicle_log/vehicle_log.py | 2 +- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py index 35400b0ca83..3770da73fcf 100644 --- a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py @@ -8,25 +8,9 @@ import unittest from frappe.utils import nowdate,flt, cstr,random_string # test_records = frappe.get_test_records('Vehicle Log') class TestVehicleLog(unittest.TestCase): - def test_make_vehicle_log(self): - license_plate=random_string(10).upper() + def test_make_vehicle_log_and_syncing_of_odometer_value(self): employee_id=frappe.db.sql("""select name from `tabEmployee` order by modified desc limit 1""")[0][0] - vehicle = frappe.get_doc({ - "doctype": "Vehicle", - "license_plate": cstr(license_plate), - "make": "Maruti", - "model": "PCM", - "last_odometer":5000, - "acquisition_date":frappe.utils.nowdate(), - "location": "Mumbai", - "chassis_no": "1234ABCD", - "uom": "Litre", - "vehicle_value":frappe.utils.flt(500000) - }) - try: - vehicle.insert() - except frappe.DuplicateEntryError: - pass + license_plate = get_vehicle(employee_id) vehicle_log = frappe.get_doc({ "doctype": "Vehicle Log", "license_plate": cstr(license_plate), @@ -36,5 +20,41 @@ class TestVehicleLog(unittest.TestCase): "fuel_qty":frappe.utils.flt(50), "price": frappe.utils.flt(500) }) - vehicle_log.insert() - vehicle_log.submit() \ No newline at end of file + vehicle_log.save() + vehicle_log.submit() + + #checking value of vehicle odometer value on submit. + vehicle = frappe.get_doc("Vehicle", license_plate) + self.assertEqual(vehicle.last_odometer, vehicle_log.odometer) + + #checking value vehicle odometer on vehicle log cancellation. + last_odometer = vehicle_log.last_odometer + current_odometer = vehicle_log.odometer + distance_travelled = current_odometer - last_odometer + + vehicle_log.cancel() + vehicle.reload() + + self.assertEqual(vehicle.last_odometer, current_odometer - distance_travelled) + + +def get_vehicle(employee_id): + license_plate=random_string(10).upper() + vehicle = frappe.get_doc({ + "doctype": "Vehicle", + "license_plate": cstr(license_plate), + "make": "Maruti", + "model": "PCM", + "employee": employee_id, + "last_odometer":5000, + "acquisition_date":frappe.utils.nowdate(), + "location": "Mumbai", + "chassis_no": "1234ABCD", + "uom": "Litre", + "vehicle_value":frappe.utils.flt(500000) + }) + try: + vehicle.insert() + except frappe.DuplicateEntryError: + pass + return license_plate \ No newline at end of file diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.py b/erpnext/hr/doctype/vehicle_log/vehicle_log.py index dfdfc0d7202..12cc1dd03a6 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.py @@ -18,7 +18,7 @@ class VehicleLog(Document): if not (service_detail.service_item and service_detail.type and service_detail.frequency and service_detail.expense_amount): frappe.throw(_("Service Item,Type,frequency and expense amount are required")) - def before_save(self): + def before_insert(self): model_details = get_make_model(self.license_plate) self.make = model_details[0] self.model = model_details[1] From 1beeb2890881740f4747ddbd3bd0a8a4c311e03a Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 20 Feb 2020 12:22:33 +0530 Subject: [PATCH 025/137] fix: check for available stock in product bundle's website warehouse (#20680) --- erpnext/utilities/product.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/utilities/product.py b/erpnext/utilities/product.py index 1c0d4c38c73..c23c1f7096d 100644 --- a/erpnext/utilities/product.py +++ b/erpnext/utilities/product.py @@ -129,6 +129,7 @@ def get_non_stock_item_status(item_code, item_warehouse_field): #if item belongs to product bundle, check if bundle items are in stock if frappe.db.exists("Product Bundle", item_code): items = frappe.get_doc("Product Bundle", item_code).get_all_children() - return all([ get_qty_in_stock(d.item_code, item_warehouse_field).in_stock for d in items ]) + bundle_warehouse = frappe.db.get_value('Item', item_code, item_warehouse_field) + return all([ get_qty_in_stock(d.item_code, item_warehouse_field, bundle_warehouse).in_stock for d in items ]) else: return 1 From 8e80c17602663ef78e3be16a187520fa148f866a Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 20 Feb 2020 12:32:09 +0530 Subject: [PATCH 026/137] chore: SINV set_status remove redundant function calls (#20661) --- .../accounts/doctype/sales_invoice/sales_invoice.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 0dc889c0b7a..0b793e847a7 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1237,25 +1237,28 @@ class SalesInvoice(SellingController): precision = self.precision("outstanding_amount") outstanding_amount = flt(self.outstanding_amount, precision) + due_date = getdate(self.due_date) + nowdate = getdate() + discountng_status = self.get_discounting_status() if not status: if self.docstatus == 2: status = "Cancelled" elif self.docstatus == 1: - if outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed': + if outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed': self.status = "Overdue and Discounted" - elif outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()): + elif outstanding_amount > 0 and due_date < nowdate: self.status = "Overdue" - elif outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.is_discounted and self.get_discounting_status()=='Disbursed': + elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discountng_status=='Disbursed': self.status = "Unpaid and Discounted" - elif outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()): + elif outstanding_amount > 0 and due_date >= nowdate: self.status = "Unpaid" #Check if outstanding amount is 0 due to credit note issued against invoice elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): self.status = "Credit Note Issued" elif self.is_return == 1: self.status = "Return" - elif outstanding_amount <=0: + elif outstanding_amount<=0: self.status = "Paid" else: self.status = "Submitted" From ae9159fbd83e8c40411dd75505d7863a7c3627e2 Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 20 Feb 2020 12:33:07 +0530 Subject: [PATCH 027/137] fix: mandatory on hold comment for purchase invoice (#20667) --- erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index d4676ff0375..737c18a8a98 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -1015,7 +1015,7 @@ def unblock_invoice(name): @frappe.whitelist() -def block_invoice(name, hold_comment, release_date): +def block_invoice(name, release_date, hold_comment=None): if frappe.db.exists('Purchase Invoice', name): pi = frappe.get_doc('Purchase Invoice', name) pi.block_invoice(hold_comment, release_date) From 4e2b9395b957bbc5d8d3c560006b9259f593d8c7 Mon Sep 17 00:00:00 2001 From: gavin Date: Thu, 20 Feb 2020 12:48:32 +0530 Subject: [PATCH 028/137] chore: drop cypress requirement (#20675) --- cypress.json | 3 - cypress/fixtures/example.json | 5 - .../opportunity/lost_reason_detail.js | 31 - cypress/plugins/index.js | 17 - cypress/support/commands.js | 25 - cypress/support/index.js | 22 - package.json | 13 +- yarn.lock | 1302 ----------------- 8 files changed, 11 insertions(+), 1407 deletions(-) delete mode 100644 cypress.json delete mode 100644 cypress/fixtures/example.json delete mode 100644 cypress/integration/opportunity/lost_reason_detail.js delete mode 100644 cypress/plugins/index.js delete mode 100644 cypress/support/commands.js delete mode 100644 cypress/support/index.js diff --git a/cypress.json b/cypress.json deleted file mode 100644 index 2be29158592..00000000000 --- a/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "baseUrl": "http://test_site_ui:8000" -} \ No newline at end of file diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json deleted file mode 100644 index da18d9352a1..00000000000 --- a/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} \ No newline at end of file diff --git a/cypress/integration/opportunity/lost_reason_detail.js b/cypress/integration/opportunity/lost_reason_detail.js deleted file mode 100644 index 9cf204889d6..00000000000 --- a/cypress/integration/opportunity/lost_reason_detail.js +++ /dev/null @@ -1,31 +0,0 @@ -context('Form', () => { - before(() => { - cy.login('Administrator', 'qwe'); - cy.visit('/desk'); - }); - - it('create a new opportunity', () => { - cy.visit('/desk#Form/Opportunity/New Opportunity 1'); - cy.get('.page-title').should('contain', 'Not Saved'); - cy.fill_field('opportunity_from', 'Customer', 'Select'); - cy.fill_field('party_name', 'Test Customer', 'Link').blur(); - cy.get('.primary-action').click(); - cy.get('.page-title').should('contain', 'Open'); - cy.get('.form-inner-toolbar button:contains("Lost")').click({ force: true }); - cy.get('.modal input[data-fieldname="lost_reason"]').as('input'); - cy.get('@input').focus().type('Higher', { delay: 200 }); - cy.get('.modal .awesomplete ul') - .should('be.visible') - .get('li:contains("Higher Price")') - .click({ force: true }); - cy.get('@input').focus().type('No Followup', { delay: 200 }); - cy.get('.modal .awesomplete ul') - .should('be.visible') - .get('li:contains("No Followup")') - .click(); - - cy.fill_field('detailed_reason', 'Test Detailed Reason', 'Text'); - cy.get('.modal button:contains("Declare Lost")').click({ force: true }); - cy.get('.page-title').should('contain', 'Lost'); - }); -}); diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js deleted file mode 100644 index cd02c3bd7a8..00000000000 --- a/cypress/plugins/index.js +++ /dev/null @@ -1,17 +0,0 @@ -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -// module.exports = (on, config) => { -// `on` is used to hook into various events Cypress emits -// `config` is the resolved Cypress config -// } diff --git a/cypress/support/commands.js b/cypress/support/commands.js deleted file mode 100644 index c1f5a772e2b..00000000000 --- a/cypress/support/commands.js +++ /dev/null @@ -1,25 +0,0 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This is will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/cypress/support/index.js b/cypress/support/index.js deleted file mode 100644 index 872df2d5d60..00000000000 --- a/cypress/support/index.js +++ /dev/null @@ -1,22 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// import frappe commands -import '../../../frappe/cypress/support/index'; -// Import commands.js using ES2015 syntax: -import './commands'; - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/package.json b/package.json index 0e09cebf56e..9701bf3a21e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,14 @@ { - "dependencies": { - "cypress": "^3.1.4" + "name": "erpnext", + "description": "Open Source ERP System powered by the Frappe Framework", + "repository": { + "type": "git", + "url": "git+https://github.com/frappe/erpnext.git" + }, + "homepage": "https://erpnext.com", + "author": "Frappe Technologies Pvt. Ltd.", + "license": "GPL-3.0", + "bugs": { + "url": "https://github.com/frappe/erpnext/issues" } } diff --git a/yarn.lock b/yarn.lock index 6f1ff10839c..fb57ccd13af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,1305 +2,3 @@ # yarn lockfile v1 -"@cypress/listr-verbose-renderer@0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#a77492f4b11dcc7c446a34b3e28721afd33c642a" - integrity sha1-p3SS9LEdzHxEajSz4ochr9M8ZCo= - dependencies: - chalk "^1.1.3" - cli-cursor "^1.0.2" - date-fns "^1.27.2" - figures "^1.7.0" - -"@cypress/xvfb@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.3.tgz#6319afdcdcff7d1505daeeaa84484d0596189860" - integrity sha512-yYrK+/bgL3hwoRHMZG4r5fyLniCy1pXex5fimtewAY6vE/jsVs8Q37UsEO03tFlcmiLnQ3rBNMaZBYTi/+C1cw== - dependencies: - debug "^3.1.0" - lodash.once "^4.1.1" - -"@types/blob-util@1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@types/blob-util/-/blob-util-1.3.3.tgz#adba644ae34f88e1dd9a5864c66ad651caaf628a" - integrity sha512-4ahcL/QDnpjWA2Qs16ZMQif7HjGP2cw3AGjHabybjw7Vm1EKu+cfQN1D78BaZbS1WJNa1opSMF5HNMztx7lR0w== - -"@types/bluebird@3.5.18": - version "3.5.18" - resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.18.tgz#6a60435d4663e290f3709898a4f75014f279c4d6" - integrity sha512-OTPWHmsyW18BhrnG5x8F7PzeZ2nFxmHGb42bZn79P9hl+GI5cMzyPgQTwNjbem0lJhoru/8vtjAFCUOu3+gE2w== - -"@types/chai-jquery@1.1.35": - version "1.1.35" - resolved "https://registry.yarnpkg.com/@types/chai-jquery/-/chai-jquery-1.1.35.tgz#9a8f0a39ec0851b2768a8f8c764158c2a2568d04" - integrity sha512-7aIt9QMRdxuagLLI48dPz96YJdhu64p6FCa6n4qkGN5DQLHnrIjZpD9bXCvV2G0NwgZ1FAmfP214dxc5zNCfgQ== - dependencies: - "@types/chai" "*" - "@types/jquery" "*" - -"@types/chai@*": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a" - integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA== - -"@types/chai@4.0.8": - version "4.0.8" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.0.8.tgz#d27600e9ba2f371e08695d90a0fe0408d89c7be7" - integrity sha512-m812CONwdZn/dMzkIJEY0yAs4apyTkTORgfB2UsMOxgkUbC205AHnm4T8I0I5gPg9MHrFc1dJ35iS75c0CJkjg== - -"@types/jquery@*": - version "3.3.29" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.29.tgz#680a2219ce3c9250483722fccf5570d1e2d08abd" - integrity sha512-FhJvBninYD36v3k6c+bVk1DSZwh7B5Dpb/Pyk3HKVsiohn0nhbefZZ+3JXbWQhFyt0MxSl2jRDdGQPHeOHFXrQ== - dependencies: - "@types/sizzle" "*" - -"@types/jquery@3.3.6": - version "3.3.6" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.6.tgz#5932ead926307ca21e5b36808257f7c926b06565" - integrity sha512-403D4wN95Mtzt2EoQHARf5oe/jEPhzBOBNrunk+ydQGW8WmkQ/E8rViRAEB1qEt/vssfGfNVD6ujP4FVeegrLg== - -"@types/lodash@4.14.87": - version "4.14.87" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.87.tgz#55f92183b048c2c64402afe472f8333f4e319a6b" - integrity sha512-AqRC+aEF4N0LuNHtcjKtvF9OTfqZI0iaBoe3dA6m/W+/YZJBZjBmW/QIZ8fBeXC6cnytSY9tBoFBqZ9uSCeVsw== - -"@types/minimatch@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/mocha@2.2.44": - version "2.2.44" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.44.tgz#1d4a798e53f35212fd5ad4d04050620171cd5b5e" - integrity sha512-k2tWTQU8G4+iSMvqKi0Q9IIsWAp/n8xzdZS4Q4YVIltApoMA00wFBFdlJnmoaK1/z7B0Cy0yPe6GgXteSmdUNw== - -"@types/sinon-chai@2.7.29": - version "2.7.29" - resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-2.7.29.tgz#4db01497e2dd1908b2bd30d1782f456353f5f723" - integrity sha512-EkI/ZvJT4hglWo7Ipf9SX+J+R9htNOMjW8xiOhce7+0csqvgoF5IXqY5Ae1GqRgNtWCuaywR5HjVa1snkTqpOw== - dependencies: - "@types/chai" "*" - "@types/sinon" "*" - -"@types/sinon@*": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.0.2.tgz#234c03dd39bfa97616b28215caea3de043c63310" - integrity sha512-YvJOqPk4kh1eQyxuASDD4MDK27XWAhtw6hJ7rRayEOkkTpZkqDWpDb4OjLVzFGdapOuUgZdnqO+71Q3utCJtcA== - -"@types/sinon@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.0.0.tgz#84e707e157ec17d3e4c2a137f41fc3f416c0551e" - integrity sha512-kcYoPw0uKioFVC/oOqafk2yizSceIQXCYnkYts9vJIwQklFRsMubTObTDrjQamUyBRd47332s85074cd/hCwxg== - -"@types/sizzle@*": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" - integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== - -ajv@^5.1.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - -ansi-escapes@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -async@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.4.0.tgz#4990200f18ea5b837c2cc4f8c031a6985c385611" - integrity sha1-SZAgDxjqW4N8LMT4wDGmmFw4VhE= - dependencies: - lodash "^4.14.0" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.6.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== - -babel-runtime@^6.18.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -bluebird@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" - integrity sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - -cachedir@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-1.3.0.tgz#5e01928bf2d95b5edd94b0942188246740e0dbc4" - integrity sha512-O1ji32oyON9laVPJL1IZ5bmwd2cB46VfpxkDequezH+15FDzzVddEyrGEeX4WusDSqKxdyFdDQDEG1yo1GoWkg== - dependencies: - os-homedir "^1.0.1" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@2.4.1, chalk@^2.0.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -check-more-types@2.24.0: - version "2.24.0" - resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" - integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= - -ci-info@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - -cli-cursor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc= - dependencies: - restore-cursor "^1.0.1" - -cli-spinners@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" - integrity sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw= - -cli-truncate@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" - integrity sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ= - dependencies: - slice-ansi "0.0.4" - string-width "^1.0.1" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -combined-stream@^1.0.6, combined-stream@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== - dependencies: - delayed-stream "~1.0.0" - -commander@2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== - -common-tags@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" - integrity sha1-EYe+Tz1M8MBCfUP3Tu8fc1AWFMA= - dependencies: - babel-runtime "^6.18.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - integrity sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc= - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -core-js@^2.4.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042" - integrity sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg== - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cypress@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.1.4.tgz#2af04da05e09f9d3871d05713b364472744c4216" - integrity sha512-8VJYtCAFqHXMnRDo4vdomR2CqfmhtReoplmbkXVspeKhKxU8WsZl0Nh5yeil8txxhq+YQwDrInItUqIm35Vw+g== - dependencies: - "@cypress/listr-verbose-renderer" "0.4.1" - "@cypress/xvfb" "1.2.3" - "@types/blob-util" "1.3.3" - "@types/bluebird" "3.5.18" - "@types/chai" "4.0.8" - "@types/chai-jquery" "1.1.35" - "@types/jquery" "3.3.6" - "@types/lodash" "4.14.87" - "@types/minimatch" "3.0.3" - "@types/mocha" "2.2.44" - "@types/sinon" "7.0.0" - "@types/sinon-chai" "2.7.29" - bluebird "3.5.0" - cachedir "1.3.0" - chalk "2.4.1" - check-more-types "2.24.0" - commander "2.11.0" - common-tags "1.4.0" - debug "3.1.0" - execa "0.10.0" - executable "4.1.1" - extract-zip "1.6.6" - fs-extra "4.0.1" - getos "3.1.0" - glob "7.1.2" - is-ci "1.0.10" - is-installed-globally "0.1.0" - lazy-ass "1.6.0" - listr "0.12.0" - lodash "4.17.11" - log-symbols "2.2.0" - minimist "1.2.0" - moment "2.22.2" - ramda "0.24.1" - request "2.87.0" - request-progress "0.3.1" - supports-color "5.1.0" - tmp "0.0.31" - url "0.11.0" - yauzl "2.8.0" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -date-fns@^1.27.2: - version "1.30.1" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" - integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== - -debug@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -elegant-spinner@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" - integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -execa@0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" - integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== - dependencies: - cross-spawn "^6.0.0" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -executable@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" - integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== - dependencies: - pify "^2.2.0" - -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g= - -extend@~3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extract-zip@1.6.6: - version "1.6.6" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" - integrity sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw= - dependencies: - concat-stream "1.6.0" - debug "2.6.9" - mkdirp "0.5.0" - yauzl "2.4.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU= - dependencies: - pend "~1.2.0" - -figures@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -fs-extra@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.1.tgz#7fc0c6c8957f983f57f306a24e5b9ddd8d0dd880" - integrity sha1-f8DGyJV/mD9X8waiTlud3Y0N2IA= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^3.0.0" - universalify "^0.1.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -getos@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.0.tgz#db3aa4df15a3295557ce5e81aa9e3e5cdfaa6567" - integrity sha512-i9vrxtDu5DlLVFcrbqUqGWYlZN/zZ4pGMICCAcZoYsX3JA54nYp8r5EThw5K+m2q3wszkx4Th746JstspB0H4Q== - dependencies: - async "2.4.0" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-dirs@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= - dependencies: - ini "^1.3.4" - -graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.1.15" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" - integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - integrity sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0= - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -ini@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -is-ci@1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" - integrity sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4= - dependencies: - ci-info "^1.0.0" - -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-installed-globally@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" - integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= - dependencies: - global-dirs "^0.1.0" - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= - dependencies: - path-is-inside "^1.0.1" - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsonfile@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" - integrity sha1-pezG9l9T9mLEQVx2daAzHQmS7GY= - optionalDependencies: - graceful-fs "^4.1.6" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -lazy-ass@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" - integrity sha1-eZllXoZGwX8In90YfRUNMyTVRRM= - -listr-silent-renderer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" - integrity sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4= - -listr-update-renderer@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz#ca80e1779b4e70266807e8eed1ad6abe398550f9" - integrity sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk= - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - elegant-spinner "^1.0.1" - figures "^1.7.0" - indent-string "^3.0.0" - log-symbols "^1.0.2" - log-update "^1.0.2" - strip-ansi "^3.0.1" - -listr-verbose-renderer@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35" - integrity sha1-ggb0z21S3cWCfl/RSYng6WWTOjU= - dependencies: - chalk "^1.1.3" - cli-cursor "^1.0.2" - date-fns "^1.27.2" - figures "^1.7.0" - -listr@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/listr/-/listr-0.12.0.tgz#6bce2c0f5603fa49580ea17cd6a00cc0e5fa451a" - integrity sha1-a84sD1YD+klYDqF81qAMwOX6RRo= - dependencies: - chalk "^1.1.3" - cli-truncate "^0.2.1" - figures "^1.7.0" - indent-string "^2.1.0" - is-promise "^2.1.0" - is-stream "^1.1.0" - listr-silent-renderer "^1.1.1" - listr-update-renderer "^0.2.0" - listr-verbose-renderer "^0.4.0" - log-symbols "^1.0.2" - log-update "^1.0.2" - ora "^0.2.3" - p-map "^1.1.1" - rxjs "^5.0.0-beta.11" - stream-to-observable "^0.1.0" - strip-ansi "^3.0.1" - -lodash.once@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= - -lodash@4.17.11, lodash@^4.14.0: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== - -log-symbols@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - -log-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" - integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg= - dependencies: - chalk "^1.0.0" - -log-update@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1" - integrity sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE= - dependencies: - ansi-escapes "^1.0.0" - cli-cursor "^1.0.2" - -mime-db@~1.37.0: - version "1.37.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" - integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== - -mime-types@^2.1.12, mime-types@~2.1.17: - version "2.1.21" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" - integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== - dependencies: - mime-db "~1.37.0" - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -mkdirp@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" - integrity sha1-HXMHam35hs2TROFecfzAWkyavxI= - dependencies: - minimist "0.0.8" - -moment@2.22.2: - version "2.22.2" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" - integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= - -object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k= - -ora@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" - integrity sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q= - dependencies: - chalk "^1.1.1" - cli-cursor "^1.0.2" - cli-spinners "^0.1.2" - object-assign "^4.0.1" - -os-homedir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - -os-tmpdir@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-map@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" - integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -pify@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -qs@~6.5.1: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -ramda@0.24.1: - version "0.24.1" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" - integrity sha1-w7d1UZfzW43DUCIoJixMkd22uFc= - -readable-stream@^2.2.2: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - -request-progress@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-0.3.1.tgz#0721c105d8a96ac6b2ce8b2c89ae2d5ecfcf6b3a" - integrity sha1-ByHBBdipasayzossia4tXs/Pazo= - dependencies: - throttleit "~0.0.2" - -request@2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - integrity sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE= - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - -rxjs@^5.0.0-beta.11: - version "5.5.12" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" - integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== - dependencies: - symbol-observable "1.0.1" - -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -semver@^5.5.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= - -sshpk@^1.7.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.0.tgz#1d4963a2fbffe58050aa9084ca20be81741c07de" - integrity sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stream-to-observable@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.1.0.tgz#45bf1d9f2d7dc09bed81f1c307c430e68b84cffe" - integrity sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4= - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -supports-color@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.1.0.tgz#058a021d1b619f7ddf3980d712ea3590ce7de3d5" - integrity sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ== - dependencies: - has-flag "^2.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= - -throttleit@~0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" - integrity sha1-z+34jmDADdlpe2H90qg0OptoDq8= - -tmp@0.0.31: - version "0.0.31" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" - integrity sha1-jzirlDjhcxXl29izZX6L+yd65Kc= - dependencies: - os-tmpdir "~1.0.1" - -tough-cookie@~2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" - integrity sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA== - dependencies: - punycode "^1.4.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -url@0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -uuid@^3.1.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= - dependencies: - fd-slicer "~1.0.1" - -yauzl@2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.8.0.tgz#79450aff22b2a9c5a41ef54e02db907ccfbf9ee2" - integrity sha1-eUUK/yKyqcWkHvVOAtuQfM+/nuI= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.0.1" From a6f56bbc3e7cd0e2fb470963975fdfe6bdc7190c Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Thu, 20 Feb 2020 08:20:09 +0100 Subject: [PATCH 029/137] chore(ci-coverage): Pin coverage 4.5.4 #20646 (#20648) * chore(ci-coverage): Pin coveralls 4.5.4 #20646 Signed-off-by: mathieu.brunot * chore: Pin coverage Signed-off-by: mathieu.brunot --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 365eb67f3dc..213445b806e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,5 +77,6 @@ install: - bench --site test_site reinstall --yes after_script: + - pip install coverage==4.5.4 - pip install python-coveralls - coveralls -b apps/erpnext -d ../../sites/.coverage From ab8aa43ffb18c5fdec4eaf618c203bb97e695201 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Thu, 20 Feb 2020 12:52:37 +0530 Subject: [PATCH 030/137] fix: changed field type which was affecting filters (#20670) --- erpnext/hr/doctype/attendance/attendance.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/hr/doctype/attendance/attendance.json b/erpnext/hr/doctype/attendance/attendance.json index bc89b368d30..20974a0b7d2 100644 --- a/erpnext/hr/doctype/attendance/attendance.json +++ b/erpnext/hr/doctype/attendance/attendance.json @@ -57,11 +57,12 @@ { "fetch_from": "employee.employee_name", "fieldname": "employee_name", - "fieldtype": "Read Only", + "fieldtype": "Data", "in_global_search": 1, "label": "Employee Name", "oldfieldname": "employee_name", - "oldfieldtype": "Data" + "oldfieldtype": "Data", + "read_only": 1 }, { "default": "Present", @@ -173,7 +174,7 @@ "icon": "fa fa-ok", "idx": 1, "is_submittable": 1, - "modified": "2019-07-29 20:35:40.845422", + "modified": "2020-02-19 14:25:32.945842", "modified_by": "Administrator", "module": "HR", "name": "Attendance", From 355051bf75ced103449e67a4bdcefdd67b7f9f63 Mon Sep 17 00:00:00 2001 From: Rohan Date: Thu, 20 Feb 2020 12:59:21 +0530 Subject: [PATCH 031/137] fix: apply url encoding to project names (#20641) --- erpnext/templates/includes/projects/project_row.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/templates/includes/projects/project_row.html b/erpnext/templates/includes/projects/project_row.html index 55b02e20045..73c83ef560b 100644 --- a/erpnext/templates/includes/projects/project_row.html +++ b/erpnext/templates/includes/projects/project_row.html @@ -1,6 +1,6 @@ {% if doc.status=="Open" %}
- +
From c74343531fe97b995c38b5a3806304397fb3ea12 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Thu, 20 Feb 2020 13:25:45 +0530 Subject: [PATCH 032/137] fix: skip earned leaves check for max leaves set to zero or less (#20536) * fix: skip earned leaves check for max leaves set to zero or less * test: earned leaves creation --- .../leave_application/test_leave_application.py | 10 +++++++++- erpnext/hr/utils.py | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py index 5dfcad6a294..fc18d7a4cab 100644 --- a/erpnext/hr/doctype/leave_application/test_leave_application.py +++ b/erpnext/hr/doctype/leave_application/test_leave_application.py @@ -409,7 +409,7 @@ class TestLeaveApplication(unittest.TestCase): self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, nowdate(), add_days(nowdate(), 8)), 21) - def test_earned_leave(self): + def test_earned_leaves_creation(self): leave_period = get_leave_period() employee = get_employee() leave_type = 'Test Earned Leave Type' @@ -437,6 +437,14 @@ class TestLeaveApplication(unittest.TestCase): i += 1 self.assertEqual(get_leave_balance_on(employee.name, leave_type, nowdate()), 6) + # validate earned leaves creation without maximum leaves + frappe.db.set_value('Leave Type', leave_type, 'max_leaves_allowed', 0) + i = 0 + while(i<6): + allocate_earned_leaves() + i += 1 + self.assertEqual(get_leave_balance_on(employee.name, leave_type, nowdate()), 9) + # test to not consider current leave in leave balance while submitting def test_current_leave_on_submit(self): employee = get_employee() diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 9b0ca4e9a1a..4f5653dc67e 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -316,7 +316,9 @@ def allocate_earned_leaves(): allocation = frappe.get_doc('Leave Allocation', allocation.name) new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves) - new_allocation = new_allocation if new_allocation <= e_leave_type.max_leaves_allowed else e_leave_type.max_leaves_allowed + + if new_allocation > e_leave_type.max_leaves_allowed and e_leave_type.max_leaves_allowed > 0: + new_allocation = e_leave_type.max_leaves_allowed if new_allocation == allocation.total_leaves_allocated: continue From 588a89f95719bdfcb7acf5711114f9868469a409 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Thu, 20 Feb 2020 13:41:00 +0530 Subject: [PATCH 033/137] fix: return null for attribute (#20684) --- .../doctype/amazon_mws_settings/amazon_methods.py | 6 ++++++ .../doctype/amazon_mws_settings/amazon_mws_settings.py | 5 ++--- .../doctype/amazon_mws_settings/xml_utils.py | 5 ++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py index 2f39dc596bf..3bc8db5e78a 100644 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py @@ -165,6 +165,9 @@ def create_item_code(amazon_item_json, sku): return item.name def create_manufacturer(amazon_item_json): + if not amazon_item_json.Product.AttributeSets.ItemAttributes.Manufacturer: + return None + existing_manufacturer = frappe.db.get_value("Manufacturer", filters={"short_name":amazon_item_json.Product.AttributeSets.ItemAttributes.Manufacturer}) @@ -177,6 +180,9 @@ def create_manufacturer(amazon_item_json): return existing_manufacturer def create_brand(amazon_item_json): + if not amazon_item_json.Product.AttributeSets.ItemAttributes.Brand: + return None + existing_brand = frappe.db.get_value("Brand", filters={"brand":amazon_item_json.Product.AttributeSets.ItemAttributes.Brand}) if not existing_brand: diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py index 249a73f9fbb..c222afbb6c1 100644 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py @@ -7,7 +7,6 @@ import frappe from frappe.model.document import Document import dateutil from frappe.custom.doctype.custom_field.custom_field import create_custom_fields -from erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods import get_products_details, get_orders class AmazonMWSSettings(Document): def validate(self): @@ -19,12 +18,12 @@ class AmazonMWSSettings(Document): def get_products_details(self): if self.enable_amazon == 1: - get_products_details() + frappe.enqueue('erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods.get_products_details') def get_order_details(self): if self.enable_amazon == 1: after_date = dateutil.parser.parse(self.after_date).strftime("%Y-%m-%d") - get_orders(after_date = after_date) + frappe.enqueue('erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods.get_orders', after_date=after_date) def schedule_get_order_details(): mws_settings = frappe.get_doc("Amazon MWS Settings") diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py index 58db669411a..a25a29f9e5f 100644 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py @@ -33,7 +33,10 @@ class object_dict(dict): def __getattr__(self, item): - d = self.__getitem__(item) + try: + d = self.__getitem__(item) + except KeyError: + return None if isinstance(d, dict) and 'value' in d and len(d) == 1: return d['value'] From df15c758f6abde9577924db779e0652c303406ce Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 20 Feb 2020 15:29:09 +0530 Subject: [PATCH 034/137] fix: Additional salary can be created only for active employee --- erpnext/hr/doctype/additional_salary/additional_salary.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/additional_salary/additional_salary.js b/erpnext/hr/doctype/additional_salary/additional_salary.js index d0f64ab51bb..18f6b8b52d5 100644 --- a/erpnext/hr/doctype/additional_salary/additional_salary.js +++ b/erpnext/hr/doctype/additional_salary/additional_salary.js @@ -8,7 +8,8 @@ frappe.ui.form.on('Additional Salary', { frm.set_query("employee", function() { return { filters: { - company: frm.doc.company + company: frm.doc.company, + status: "Active" } }; }); From 9921d28ea7357be1eb1d2791bcfdd320fb0bf08f Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 24 Feb 2020 18:45:47 +0530 Subject: [PATCH 035/137] fix: account dashboard not working --- .../account_balance_timeline.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py index 43acded3a98..a9b3d7c4cc2 100644 --- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py +++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe, json from frappe import _ -from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate +from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form from erpnext.accounts.report.general_ledger.general_ledger import execute from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending @@ -30,8 +30,13 @@ def get(chart_name = None, chart = None, no_cache = None, from_date = None, to_d account = filters.get("account") company = filters.get("company") - if not account and chart: - frappe.throw(_("Account is not set for the dashboard chart {0}").format(chart)) + if not account and chart_name: + frappe.throw(_("Account is not set for the dashboard chart {0}") + .format(get_link_to_form("Dashboard Chart", chart_name))) + + if not frappe.db.exists("Account", account) and chart_name: + frappe.throw(_("Account {0} does not exists in the dashboard chart {1}") + .format(account, get_link_to_form("Dashboard Chart", chart_name))) if not to_date: to_date = nowdate() From a20bd89c20819a5ab6e6c31f03a3fab7efc29391 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 26 Feb 2020 11:25:30 +0530 Subject: [PATCH 036/137] fix: reorder material request not created if doctype has custom mandatory field (#20720) --- erpnext/stock/reorder_item.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py index 39fb0240236..97776739a87 100644 --- a/erpnext/stock/reorder_item.py +++ b/erpnext/stock/reorder_item.py @@ -116,6 +116,8 @@ def create_material_request(material_requests): else: exceptions_list.append(frappe.get_traceback()) + frappe.log_error(frappe.get_traceback()) + for request_type in material_requests: for company in material_requests[request_type]: try: @@ -158,6 +160,7 @@ def create_material_request(material_requests): schedule_dates = [d.schedule_date for d in mr.items] mr.schedule_date = max(schedule_dates or [nowdate()]) + mr.flags.ignore_mandatory = True mr.insert() mr.submit() mr_list.append(mr) From 0aa7aa5996c090ef0cc050570324d80a81c23819 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 26 Feb 2020 11:27:49 +0530 Subject: [PATCH 037/137] fix: rate and amount in material request copying from sales order (#20718) --- .../material_request_item/material_request_item.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json index 795971b5e3d..9d1dafb136b 100644 --- a/erpnext/stock/doctype/material_request_item/material_request_item.json +++ b/erpnext/stock/doctype/material_request_item/material_request_item.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "hash", "creation": "2013-02-22 01:28:02", "doctype": "DocType", @@ -185,12 +186,14 @@ { "fieldname": "rate", "fieldtype": "Currency", - "label": "Rate" + "label": "Rate", + "no_copy": 1 }, { "fieldname": "amount", "fieldtype": "Currency", "label": "Amount", + "no_copy": 1, "read_only": 1 }, { @@ -407,7 +410,8 @@ ], "idx": 1, "istable": 1, - "modified": "2019-06-02 06:49:36.493957", + "links": [], + "modified": "2020-02-25 03:09:10.698967", "modified_by": "Administrator", "module": "Stock", "name": "Material Request Item", From 2a8981929af9d9ad074ed81fb3b7762f8117c473 Mon Sep 17 00:00:00 2001 From: Saqib Date: Wed, 26 Feb 2020 11:36:38 +0530 Subject: [PATCH 038/137] perf: search for customer's return invoices then filter out gl_entries (#20710) --- .../payment_reconciliation.py | 18 ++++++++++++------ .../doctype/sales_invoice/sales_invoice.py | 3 +++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 2c04a27b0cd..30804961861 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -92,6 +92,7 @@ class PaymentReconciliation(Document): FROM `tab{doc}`, `tabGL Entry` WHERE (`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no) + and `tab{doc}`.{party_type_field} = %(party)s and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL and `tabGL Entry`.against_voucher_type = %(voucher_type)s and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s @@ -99,12 +100,17 @@ class PaymentReconciliation(Document): GROUP BY `tab{doc}`.name Having amount > 0 - """.format(doc=voucher_type, dr_or_cr=dr_or_cr, reconciled_dr_or_cr=reconciled_dr_or_cr), { - 'party': self.party, - 'party_type': self.party_type, - 'voucher_type': voucher_type, - 'account': self.receivable_payable_account - }, as_dict=1) + """.format( + doc=voucher_type, + dr_or_cr=dr_or_cr, + reconciled_dr_or_cr=reconciled_dr_or_cr, + party_type_field=frappe.scrub(self.party_type)), + { + 'party': self.party, + 'party_type': self.party_type, + 'voucher_type': voucher_type, + 'account': self.receivable_payable_account + }, as_dict=1) def add_payment_entries(self, entries): self.set('payments', []) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 0b793e847a7..d0fe4f4832a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1523,6 +1523,9 @@ def get_loyalty_programs(customer): else: return lp_details +def on_doctype_update(): + frappe.db.add_index("Sales Invoice", ["customer", "is_return", "return_against"]) + @frappe.whitelist() def create_invoice_discounting(source_name, target_doc=None): invoice = frappe.get_doc("Sales Invoice", source_name) From 6eaa542709d8bae385139655f5ef6f1cef0b883d Mon Sep 17 00:00:00 2001 From: RJPvT <48353029+RJPvT@users.noreply.github.com> Date: Wed, 26 Feb 2020 07:29:06 +0100 Subject: [PATCH 039/137] fix: smaller then instead of bigger then :-( dumb mistake v12 #20693 (#20701) --- erpnext/projects/doctype/task/task.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index f2ba80f096f..7cf4150298c 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -212,10 +212,10 @@ def set_multiple_status(names, status): task.save() def set_tasks_as_overdue(): - tasks = frappe.get_all("Task", filters={'status':['not in',['Cancelled', 'Closed']]}) + tasks = frappe.get_all("Task", filters={"status": ["not in", ["Cancelled", "Completed"]]}, fields=["name", "status", "review_date"]) for task in tasks: - if frappe.db.get_value("Task", task.name, "status") in 'Pending Review': - if getdate(frappe.db.get_value("Task", task.name, "review_date")) < getdate(today()): + if task.status == "Pending Review": + if getdate(task.review_date) > getdate(today()): continue frappe.get_doc("Task", task.name).update_status() From 39861c270c0dd457837755cea480cc4b08704ebc Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 26 Feb 2020 12:51:53 +0530 Subject: [PATCH 040/137] fix: same free item not working for pricing rule (#20713) --- .../doctype/pricing_rule/pricing_rule.py | 2 +- .../doctype/pricing_rule/test_pricing_rule.py | 60 +++++++++++++++++++ .../accounts/doctype/pricing_rule/utils.py | 9 +-- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 1d8d9dbcef5..fc0d8b16f71 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -252,7 +252,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa if pricing_rule.price_or_product_discount == "Price": apply_price_discount_rule(pricing_rule, item_details, args) else: - get_product_discount_rule(pricing_rule, item_details, doc) + get_product_discount_rule(pricing_rule, item_details, args, doc) item_details.has_pricing_rule = 1 diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 9c1fef69fac..2da71dfd0e0 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -326,6 +326,66 @@ class TestPricingRule(unittest.TestCase): self.assertEquals(item.discount_amount, 110) self.assertEquals(item.rate, 990) + def test_pricing_rule_for_product_discount_on_same_item(self): + frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule') + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule", + "apply_on": "Item Code", + "currency": "USD", + "items": [{ + "item_code": "_Test Item", + }], + "selling": 1, + "rate_or_discount": "Discount Percentage", + "rate": 0, + "min_qty": 0, + "max_qty": 7, + "discount_percentage": 17.5, + "price_or_product_discount": "Product", + "same_item": 1, + "free_qty": 1, + "company": "_Test Company" + } + frappe.get_doc(test_record.copy()).insert() + + # With pricing rule + so = make_sales_order(item_code="_Test Item", qty=1) + so.load_from_db() + self.assertEqual(so.items[1].is_free_item, 1) + self.assertEqual(so.items[1].item_code, "_Test Item") + + + def test_pricing_rule_for_product_discount_on_different_item(self): + frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule') + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule", + "apply_on": "Item Code", + "currency": "USD", + "items": [{ + "item_code": "_Test Item", + }], + "selling": 1, + "rate_or_discount": "Discount Percentage", + "rate": 0, + "min_qty": 0, + "max_qty": 7, + "discount_percentage": 17.5, + "price_or_product_discount": "Product", + "same_item": 0, + "free_item": "_Test Item 2", + "free_qty": 1, + "company": "_Test Company" + } + frappe.get_doc(test_record.copy()).insert() + + # With pricing rule + so = make_sales_order(item_code="_Test Item", qty=1) + so.load_from_db() + self.assertEqual(so.items[1].is_free_item, 1) + self.assertEqual(so.items[1].item_code, "_Test Item 2") + def make_pricing_rule(**args): args = frappe._dict(args) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index e475563c77c..a2bb2ee927d 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -435,7 +435,7 @@ def apply_pricing_rule_on_transaction(doc): doc.calculate_taxes_and_totals() elif d.price_or_product_discount == 'Product': item_details = frappe._dict({'parenttype': doc.doctype}) - get_product_discount_rule(d, item_details, doc) + get_product_discount_rule(d, item_details, doc=doc) apply_pricing_rule_for_free_items(doc, item_details.free_item_data) doc.set_missing_values() @@ -443,9 +443,10 @@ def get_applied_pricing_rules(item_row): return (item_row.get("pricing_rules").split(',') if item_row.get("pricing_rules") else []) -def get_product_discount_rule(pricing_rule, item_details, doc=None): - free_item = (pricing_rule.free_item - if not pricing_rule.same_item or pricing_rule.apply_on == 'Transaction' else item_details.item_code) +def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None): + free_item = pricing_rule.free_item + if pricing_rule.same_item: + free_item = item_details.item_code or args.item_code if not free_item: frappe.throw(_("Free item not set in the pricing rule {0}") From 5475b5f562149699498f405c9f40fb36521e3d1e Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Wed, 26 Feb 2020 14:50:52 +0530 Subject: [PATCH 041/137] fix: validated leave allocation (#20635) * fix: validated leave allocation * fix: changes requested * Update erpnext/hr/doctype/leave_encashment/leave_encashment.py Co-Authored-By: Nabin Hait Co-authored-by: Nabin Hait --- erpnext/hr/doctype/leave_encashment/leave_encashment.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py index 42f0179baf5..ad2cc02fd7c 100644 --- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py +++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py @@ -64,6 +64,9 @@ class LeaveEncashment(Document): allocation = self.get_leave_allocation() + if not allocation: + frappe.throw(_("No Leaves Allocated to Employee: {0} for Leave Type: {1}").format(self.employee, self.leave_type)) + self.leave_balance = allocation.total_leaves_allocated - allocation.carry_forwarded_leaves_count\ - get_unused_leaves(self.employee, self.leave_type, allocation.from_date, self.encashment_date) @@ -116,4 +119,4 @@ def create_leave_encashment(leave_allocation): leave_type=allocation.leave_type, encashment_date=allocation.to_date )) - leave_encashment.insert(ignore_permissions=True) \ No newline at end of file + leave_encashment.insert(ignore_permissions=True) From acbc4f648d8ae40c3b6d6d53104399c8aa13cec5 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Wed, 26 Feb 2020 17:17:06 +0530 Subject: [PATCH 042/137] fix: Mandatory bank account error fix (#20734) * fix: Mandatory bank account error fix * fix: SQL condition --- .../bank_reconciliation/bank_reconciliation.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 52bbe3327a8..2436b15dd4d 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -13,9 +13,11 @@ form_grid_templates = { class BankReconciliation(Document): def get_payment_entries(self): - if not (self.bank_account and self.from_date and self.to_date): - msgprint(_("Bank Account, From Date and To Date are Mandatory")) - return + if not (self.from_date and self.to_date): + frappe.throw(_("From Date and To Date are Mandatory")) + + if not self.account: + frappe.throw(_("Account is mandatory to get payment entries")) condition = "" if not self.include_reconciled_entries: @@ -37,6 +39,11 @@ class BankReconciliation(Document): order by t1.posting_date ASC, t1.name DESC """, {"condition":condition, "account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1) + condition = '' + + if self.bank_account: + condition += 'and bank_account = %(bank_account)s' + payment_entries = frappe.db.sql(""" select "Payment Entry" as payment_document, name as payment_entry, @@ -49,10 +56,10 @@ class BankReconciliation(Document): where (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1 and posting_date >= %(from)s and posting_date <= %(to)s - and bank_account = %(bank_account)s + {condition} order by posting_date ASC, name DESC - """, {"account": self.account, "from":self.from_date, + """.format(condition=condition), {"account": self.account, "from":self.from_date, "to": self.to_date, "bank_account": self.bank_account}, as_dict=1) pos_entries = [] From 4e3ad9c3f2768656ee3e5095d76de0e8ad8b91e1 Mon Sep 17 00:00:00 2001 From: Marica Date: Wed, 26 Feb 2020 18:51:35 +0530 Subject: [PATCH 043/137] fix: Lock stock ledger entries that are being reposted. (#20739) - If stock ledger entries are being reposted, don't let any other transaction apply itself on the same. --- erpnext/controllers/stock_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 2b47a2c09b8..11c61a7f714 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -420,7 +420,7 @@ def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, f for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no from `tabStock Ledger Entry` sle where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition} - order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc""".format(condition=condition), + order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition), tuple([posting_date, posting_time] + values), as_dict=True): future_stock_vouchers.append([d.voucher_type, d.voucher_no]) From 30ad21b7d8b9f91f2533b098cea4c887b80dded6 Mon Sep 17 00:00:00 2001 From: Rohan Date: Wed, 26 Feb 2020 18:53:48 +0530 Subject: [PATCH 044/137] fix: sort Issues chronologically (#20740) --- erpnext/support/doctype/issue/issue.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json index 222554bda13..51b49e8049b 100644 --- a/erpnext/support/doctype/issue/issue.json +++ b/erpnext/support/doctype/issue/issue.json @@ -363,8 +363,9 @@ ], "icon": "fa fa-ticket", "idx": 7, - "modified": "2019-09-11 09:03:57.465623", - "modified_by": "himanshu@erpnext.com", + "links": [], + "modified": "2020-02-26 02:19:49.477928", + "modified_by": "Administrator", "module": "Support", "name": "Issue", "owner": "Administrator", @@ -384,9 +385,9 @@ "quick_entry": 1, "search_fields": "status,customer,subject,raised_by", "sort_field": "modified", - "sort_order": "ASC", + "sort_order": "DESC", "timeline_field": "customer", "title_field": "subject", "track_changes": 1, "track_seen": 1 -} \ No newline at end of file +} From 45329232b3d4076f5acfcfa637ae0f15990c51c8 Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 27 Feb 2020 12:51:23 +0530 Subject: [PATCH 045/137] fix: only update items if rate or qty changed (#20743) --- erpnext/controllers/accounts_controller.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 001da5b5ea8..5abe7366d0f 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1200,6 +1200,8 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code")) else: child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname")) + if flt(child_item.get("rate")) == flt(d.get("rate")) and flt(child_item.get("qty")) == flt(d.get("qty")): + continue if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty): frappe.throw(_("Cannot set quantity less than delivered quantity")) From fe337dfb66d709be2c91f8d4f24799e6f3264ba5 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 27 Feb 2020 14:27:43 +0530 Subject: [PATCH 046/137] fix: serial no material transfer performance issue (#20722) --- erpnext/stock/doctype/serial_no/serial_no.py | 84 ++++++++++++------- .../stock_ledger_entry.json | 3 +- erpnext/stock/utils.py | 2 +- 3 files changed, 58 insertions(+), 31 deletions(-) diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 50f27c18e31..31f84c9aaed 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -205,6 +205,7 @@ def process_serial_no(sle): def validate_serial_no(sle, item_det): serial_nos = get_serial_nos(sle.serial_no) if sle.serial_no else [] + validate_material_transfer_entry(sle) if item_det.has_serial_no==0: if serial_nos: @@ -224,7 +225,9 @@ def validate_serial_no(sle, item_det): for serial_no in serial_nos: if frappe.db.exists("Serial No", serial_no): - sr = frappe.get_doc("Serial No", serial_no) + sr = frappe.db.get_value("Serial No", serial_no, ["name", "item_code", "batch_no", "sales_order", + "delivery_document_no", "delivery_document_type", "warehouse", + "purchase_document_no", "company"], as_dict=1) if sr.item_code!=sle.item_code: if not allow_serial_nos_with_different_item(serial_no, sle): @@ -305,6 +308,19 @@ def validate_serial_no(sle, item_det): frappe.throw(_("Cannot cancel {0} {1} because Serial No {2} does not belong to the warehouse {3}") .format(sle.voucher_type, sle.voucher_no, serial_no, sle.warehouse)) +def validate_material_transfer_entry(sle_doc): + sle_doc.update({ + "skip_update_serial_no": False, + "skip_serial_no_validaiton": False + }) + + if (sle_doc.voucher_type == "Stock Entry" and sle_doc.is_cancelled == "No" and + frappe.get_cached_value("Stock Entry", sle_doc.voucher_no, "purpose") == "Material Transfer"): + if sle_doc.actual_qty < 0: + sle_doc.skip_update_serial_no = True + else: + sle_doc.skip_serial_no_validaiton = True + def validate_so_serial_no(sr, sales_order,): if not sr.sales_order or sr.sales_order!= sales_order: frappe.throw(_("""Sales Order {0} has reservation for item {1}, you can @@ -312,7 +328,8 @@ def validate_so_serial_no(sr, sales_order,): be delivered""").format(sales_order, sr.item_code, sr.name)) def has_duplicate_serial_no(sn, sle): - if sn.warehouse and sle.voucher_type != 'Stock Reconciliation': + if (sn.warehouse and not sle.skip_serial_no_validaiton + and sle.voucher_type != 'Stock Reconciliation'): return True if sn.company != sle.company: @@ -337,7 +354,7 @@ def allow_serial_nos_with_different_item(sle_serial_no, sle): """ allow_serial_nos = False if sle.voucher_type=="Stock Entry" and cint(sle.actual_qty) > 0: - stock_entry = frappe.get_doc("Stock Entry", sle.voucher_no) + stock_entry = frappe.get_cached_doc("Stock Entry", sle.voucher_no) if stock_entry.purpose in ("Repack", "Manufacture"): for d in stock_entry.get("items"): if d.serial_no and (d.s_warehouse if sle.is_cancelled=="No" else d.t_warehouse): @@ -348,6 +365,7 @@ def allow_serial_nos_with_different_item(sle_serial_no, sle): return allow_serial_nos def update_serial_nos(sle, item_det): + if sle.skip_update_serial_no: return if sle.is_cancelled == "No" and not sle.serial_no and cint(sle.actual_qty) > 0 \ and item_det.has_serial_no == 1 and item_det.serial_no_series: serial_nos = get_auto_serial_nos(item_det.serial_no_series, sle.actual_qty) @@ -367,22 +385,16 @@ def auto_make_serial_nos(args): serial_nos = get_serial_nos(args.get('serial_no')) created_numbers = [] for serial_no in serial_nos: + is_new = False if frappe.db.exists("Serial No", serial_no): - sr = frappe.get_doc("Serial No", serial_no) - sr.via_stock_ledger = True - sr.item_code = args.get('item_code') - sr.warehouse = args.get('warehouse') if args.get('actual_qty', 0) > 0 else None - sr.batch_no = args.get('batch_no') - sr.location = args.get('location') - sr.company = args.get('company') - sr.supplier = args.get('supplier') - if sr.sales_order and args.get('voucher_type') == "Stock Entry" \ - and not args.get('actual_qty', 0) > 0: - sr.sales_order = None - sr.update_serial_no_reference() - sr.save(ignore_permissions=True) + sr = frappe.get_cached_doc("Serial No", serial_no) elif args.get('actual_qty', 0) > 0: - created_numbers.append(make_serial_no(serial_no, args)) + sr = frappe.new_doc("Serial No") + is_new = True + + sr = update_args_for_serial_no(sr, serial_no, args, is_new=is_new) + if is_new: + created_numbers.append(sr.name) form_links = list(map(lambda d: frappe.utils.get_link_to_form('Serial No', d), created_numbers)) if len(form_links) == 1: @@ -399,20 +411,34 @@ def get_serial_nos(serial_no): return [s.strip() for s in cstr(serial_no).strip().upper().replace(',', '\n').split('\n') if s.strip()] -def make_serial_no(serial_no, args): - sr = frappe.new_doc("Serial No") - sr.serial_no = serial_no - sr.item_code = args.get('item_code') - sr.company = args.get('company') - sr.batch_no = args.get('batch_no') - sr.via_stock_ledger = args.get('via_stock_ledger') or True - sr.warehouse = args.get('warehouse') +def update_args_for_serial_no(serial_no_doc, serial_no, args, is_new=False): + serial_no_doc.update({ + "item_code": args.get("item_code"), + "company": args.get("company"), + "batch_no": args.get("batch_no"), + "via_stock_ledger": args.get("via_stock_ledger") or True, + "supplier": args.get("supplier"), + "location": args.get("location"), + "warehouse": (args.get("warehouse") + if args.get("actual_qty", 0) > 0 else None) + }) - sr.validate_item() - sr.update_serial_no_reference(serial_no) - sr.db_insert() + if is_new: + serial_no_doc.serial_no = serial_no - return sr.name + if (serial_no_doc.sales_order and args.get("voucher_type") == "Stock Entry" + and not args.get("actual_qty", 0) > 0): + serial_no_doc.sales_order = None + + serial_no_doc.validate_item() + serial_no_doc.update_serial_no_reference(serial_no) + + if is_new: + serial_no_doc.db_insert() + else: + serial_no_doc.db_update() + + return serial_no_doc def update_serial_nos_after_submit(controller, parentfield): stock_ledger_entries = frappe.db.sql("""select voucher_detail_no, serial_no, actual_qty, warehouse diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json index c9eba71b0d0..c03eb79eeca 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json @@ -240,6 +240,7 @@ "options": "Company", "print_width": "150px", "read_only": 1, + "search_index": 1, "width": "150px" }, { @@ -274,7 +275,7 @@ "icon": "fa fa-list", "idx": 1, "in_create": 1, - "modified": "2019-11-27 12:17:31.522675", + "modified": "2020-02-25 22:53:33.504681", "modified_by": "Administrator", "module": "Stock", "name": "Stock Ledger Entry", diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 2c6c95393bc..f3381c76091 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -136,7 +136,7 @@ def get_bin(item_code, warehouse): bin_obj.flags.ignore_permissions = 1 bin_obj.insert() else: - bin_obj = frappe.get_doc('Bin', bin) + bin_obj = frappe.get_cached_doc('Bin', bin) bin_obj.flags.ignore_permissions = True return bin_obj From d952e71d970391d0cd7f96ec3a72623aa9ed1f7c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 27 Feb 2020 16:01:47 +0530 Subject: [PATCH 047/137] fix: Journal Entry not being fetched in Bank Reconciliation --- .../doctype/bank_reconciliation/bank_reconciliation.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 2436b15dd4d..883c4207ea9 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -21,7 +21,7 @@ class BankReconciliation(Document): condition = "" if not self.include_reconciled_entries: - condition = " and (clearance_date is null or clearance_date='0000-00-00')" + condition = "and clearance_date IS NULL or clearance_date='0000-00-00'" journal_entries = frappe.db.sql(""" select @@ -34,11 +34,10 @@ class BankReconciliation(Document): where t2.parent = t1.name and t2.account = %(account)s and t1.docstatus=1 and t1.posting_date >= %(from)s and t1.posting_date <= %(to)s - and ifnull(t1.is_opening, 'No') = 'No' %(condition)s + and ifnull(t1.is_opening, 'No') = 'No' {condition} group by t2.account, t1.name order by t1.posting_date ASC, t1.name DESC - """, {"condition":condition, "account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1) - + """.format(condition=condition), {"account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1, debug=1) condition = '' if self.bank_account: From 5fb66a395302906151a6d6362094bf253d18ad1a Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 27 Feb 2020 16:04:01 +0530 Subject: [PATCH 048/137] fix: Remove debug statement --- .../doctype/bank_reconciliation/bank_reconciliation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 883c4207ea9..8900767324c 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -21,7 +21,7 @@ class BankReconciliation(Document): condition = "" if not self.include_reconciled_entries: - condition = "and clearance_date IS NULL or clearance_date='0000-00-00'" + condition = "and (clearance_date IS NULL or clearance_date='0000-00-00')" journal_entries = frappe.db.sql(""" select @@ -37,7 +37,7 @@ class BankReconciliation(Document): and ifnull(t1.is_opening, 'No') = 'No' {condition} group by t2.account, t1.name order by t1.posting_date ASC, t1.name DESC - """.format(condition=condition), {"account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1, debug=1) + """.format(condition=condition), {"account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1) condition = '' if self.bank_account: From f08b5e486627e44bd230c6b484210a609287e167 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 27 Feb 2020 19:07:39 +0530 Subject: [PATCH 049/137] feat: ignore permission when deleting linked emails (#20753) --- erpnext/setup/doctype/company/delete_company_transactions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py index 3052191943c..9979bc51e3a 100644 --- a/erpnext/setup/doctype/company/delete_company_transactions.py +++ b/erpnext/setup/doctype/company/delete_company_transactions.py @@ -106,11 +106,11 @@ def delete_lead_addresses(company_name): frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads))) def delete_communications(doctype, company_name, company_fieldname): - + refrence_docs = frappe.get_all(doctype, filters={company_fieldname:company_name}) reference_doctype_names = [r.name for r in refrence_docs] communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in",reference_doctype_names]}) communication_names = [c.name for c in communications] - frappe.delete_doc("Communication",communication_names) + frappe.delete_doc("Communication", communication_names, ignore_permissions=True) From d17e0b5acab4812fc800b243de0cec09314ac823 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Fri, 28 Feb 2020 12:29:11 +0530 Subject: [PATCH 050/137] fix: Item Wise report query fix (#20761) --- .../item_wise_purchase_register.py | 8 ++------ .../item_wise_sales_register.py | 10 +++------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 8b6359c134d..4523f66deb4 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -306,10 +306,6 @@ def get_conditions(filters): def get_items(filters, additional_query_columns): conditions = get_conditions(filters) - match_conditions = frappe.build_match_conditions("Purchase Invoice") - - if match_conditions: - match_conditions = " and {0} ".format(match_conditions) if additional_query_columns: additional_query_columns = ', ' + ', '.join(additional_query_columns) @@ -327,8 +323,8 @@ def get_items(filters, additional_query_columns): `tabPurchase Invoice`.supplier_name, `tabPurchase Invoice`.mode_of_payment {0} from `tabPurchase Invoice`, `tabPurchase Invoice Item` where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and - `tabPurchase Invoice`.docstatus = 1 %s %s - """.format(additional_query_columns) % (conditions, match_conditions), filters, as_dict=1) + `tabPurchase Invoice`.docstatus = 1 %s + """.format(additional_query_columns) % (conditions), filters, as_dict=1) def get_aii_accounts(): return dict(frappe.db.sql("select name, stock_received_but_not_billed from tabCompany")) diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 2cc2db6ca59..786e04dd5aa 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -119,7 +119,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns) data.append(total_row_map.get('total_row')) skip_total_row = 1 - + return columns, data, None, None, None, skip_total_row def get_columns(additional_table_columns, filters): @@ -370,10 +370,6 @@ def get_group_by_conditions(filters, doctype): def get_items(filters, additional_query_columns): conditions = get_conditions(filters) - match_conditions = frappe.build_match_conditions("Sales Invoice") - - if match_conditions: - match_conditions = " and {0} ".format(match_conditions) if additional_query_columns: additional_query_columns = ', ' + ', '.join(additional_query_columns) @@ -394,8 +390,8 @@ def get_items(filters, additional_query_columns): `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0} from `tabSales Invoice`, `tabSales Invoice Item` where `tabSales Invoice`.name = `tabSales Invoice Item`.parent - and `tabSales Invoice`.docstatus = 1 {1} {2} - """.format(additional_query_columns or '', conditions, match_conditions), filters, as_dict=1) #nosec + and `tabSales Invoice`.docstatus = 1 {1} + """.format(additional_query_columns or '', conditions), filters, as_dict=1) #nosec def get_delivery_notes_against_sales_order(item_list): so_dn_map = frappe._dict() From 3fcd575f53c71f9467da43e798037a9b4ce09e8a Mon Sep 17 00:00:00 2001 From: marination Date: Fri, 28 Feb 2020 12:58:41 +0530 Subject: [PATCH 051/137] chore: Rearranged Buying Module Dashboard --- erpnext/config/buying.py | 54 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py index 6f5ab32b631..1d4054786e6 100644 --- a/erpnext/config/buying.py +++ b/erpnext/config/buying.py @@ -7,6 +7,13 @@ def get_data(): "label": _("Purchasing"), "icon": "fa fa-star", "items": [ + { + "type": "doctype", + "name": "Material Request", + "onboard": 1, + "dependencies": ["Item"], + "description": _("Request for purchase."), + }, { "type": "doctype", "name": "Purchase Order", @@ -20,13 +27,6 @@ def get_data(): "onboard": 1, "dependencies": ["Item", "Supplier"] }, - { - "type": "doctype", - "name": "Material Request", - "onboard": 1, - "dependencies": ["Item"], - "description": _("Request for purchase."), - }, { "type": "doctype", "name": "Request for Quotation", @@ -63,6 +63,11 @@ def get_data(): "name": "Price List", "description": _("Price List master.") }, + { + "type": "doctype", + "name": "Pricing Rule", + "description": _("Rules for applying pricing and discount.") + }, { "type": "doctype", "name": "Product Bundle", @@ -80,11 +85,6 @@ def get_data(): "type": "doctype", "name": "Promotional Scheme", "description": _("Rules for applying different promotional schemes.") - }, - { - "type": "doctype", - "name": "Pricing Rule", - "description": _("Rules for applying pricing and discount.") } ] }, @@ -149,13 +149,6 @@ def get_data(): "reference_doctype": "Purchase Order", "onboard": 1 }, - { - "type": "report", - "is_query_report": True, - "name": "Supplier-Wise Sales Analytics", - "reference_doctype": "Stock Ledger Entry", - "onboard": 1 - }, { "type": "report", "is_query_report": True, @@ -177,6 +170,16 @@ def get_data(): "reference_doctype": "Material Request", "onboard": 1, }, + { + "type": "report", + "is_query_report": True, + "name": "Address And Contacts", + "label": _("Supplier Addresses And Contacts"), + "reference_doctype": "Address", + "route_options": { + "party_type": "Supplier" + } + } ] }, { @@ -226,18 +229,15 @@ def get_data(): { "type": "report", "is_query_report": True, - "name": "Material Requests for which Supplier Quotations are not created", - "reference_doctype": "Material Request" + "name": "Supplier-Wise Sales Analytics", + "reference_doctype": "Stock Ledger Entry", + "onboard": 1 }, { "type": "report", "is_query_report": True, - "name": "Address And Contacts", - "label": _("Supplier Addresses And Contacts"), - "reference_doctype": "Address", - "route_options": { - "party_type": "Supplier" - } + "name": "Material Requests for which Supplier Quotations are not created", + "reference_doctype": "Material Request" } ] }, From 1041516e8ef43640c5ff48c80f92f346c97a6519 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 2 Mar 2020 15:00:43 +0530 Subject: [PATCH 052/137] fix: reconciled entries showing in bank reco (#20788) --- .../accounts/doctype/bank_reconciliation/bank_reconciliation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 8900767324c..48fd154a4db 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -38,7 +38,6 @@ class BankReconciliation(Document): group by t2.account, t1.name order by t1.posting_date ASC, t1.name DESC """.format(condition=condition), {"account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1) - condition = '' if self.bank_account: condition += 'and bank_account = %(bank_account)s' From 27163e60bbabea83ad85f62bc55af7c015d1eec7 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 2 Mar 2020 15:03:18 +0530 Subject: [PATCH 053/137] feat: link serial no to batch no (#20779) * feat: link serial no to batch no * fix: test cases --- erpnext/controllers/stock_controller.py | 4 ++++ .../purchase_receipt/test_purchase_receipt.py | 23 +++++++++++++++++++ .../stock/doctype/serial_no/serial_no.json | 6 +++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 11c61a7f714..2ab1575ee21 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -239,6 +239,10 @@ class StockController(AccountsController): for d in self.items: if not d.batch_no: continue + serial_nos = [d.name for d in frappe.get_all("Serial No", {'batch_no': d.batch_no})] + if serial_nos: + frappe.db.set_value("Serial No", { 'name': ['in', serial_nos] }, "batch_no", None) + d.batch_no = None d.db_set("batch_no", None) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index aa09d3bfe5f..7ea84e99131 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -7,6 +7,7 @@ import frappe, erpnext import frappe.defaults from frappe.utils import cint, flt, cstr, today, random_string from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice +from erpnext.stock.doctype.item.test_item import create_item from erpnext import set_perpetual_inventory from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError from erpnext.accounts.doctype.account.test_account import get_inventory_account @@ -50,6 +51,28 @@ class TestPurchaseReceipt(unittest.TestCase): self.assertEqual(current_bin_stock_value, existing_bin_stock_value + 250) self.assertFalse(get_gl_entries("Purchase Receipt", pr.name)) + + def test_batched_serial_no_purchase(self): + item = frappe.get_doc("Item", { 'item_name': 'Batched Serialized Item' }) + if not item: + item = create_item("Batched Serialized Item") + item.has_batch_no = 1 + item.create_new_batch = 1 + item.has_serial_no = 1 + item.batch_number_series = "BS-BATCH-.##" + item.serial_no_series = "BS-.####" + item.save() + + pr = make_purchase_receipt(item_code=item.name, qty=5, rate=500) + + self.assertTrue(frappe.db.get_value('Batch', {'item': item.name, 'reference_name': pr.name})) + + pr.load_from_db() + batch_no = pr.items[0].batch_no + pr.cancel() + + self.assertFalse(frappe.db.get_value('Batch', {'item': item.name, 'reference_name': pr.name})) + self.assertFalse(frappe.db.get_all('Serial No', {'batch_no': batch_no})) def test_purchase_receipt_gl_entry(self): pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", get_multiple_items = True, get_taxes_and_charges = True) diff --git a/erpnext/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json index 712aadc5254..fb28b5c079d 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.json +++ b/erpnext/stock/doctype/serial_no/serial_no.json @@ -6,6 +6,7 @@ "description": "Distinct unit of an Item", "doctype": "DocType", "document_type": "Setup", + "engine": "InnoDB", "field_order": [ "details", "column_break0", @@ -104,10 +105,11 @@ }, { "fieldname": "batch_no", - "fieldtype": "Data", + "fieldtype": "Link", "in_list_view": 1, "in_standard_filter": 1, "label": "Batch No", + "options": "Batch", "read_only": 1 }, { @@ -425,7 +427,7 @@ ], "icon": "fa fa-barcode", "idx": 1, - "modified": "2019-08-07 17:28:32.243280", + "modified": "2020-02-28 19:31:09.357323", "modified_by": "Administrator", "module": "Stock", "name": "Serial No", From a6bf96322bb1d6d51e45d895682472c03ab2b4aa Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 2 Mar 2020 15:19:28 +0530 Subject: [PATCH 054/137] chore: control reposting of future gl entries with flags (#20775) --- erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py | 2 +- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 2 +- erpnext/controllers/stock_controller.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 737c18a8a98..518c4d36af4 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -368,7 +368,7 @@ class PurchaseInvoice(BuyingController): update_outstanding_amt(self.credit_to, "Supplier", self.supplier, self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name) - if repost_future_gle and cint(self.update_stock) and self.auto_accounting_for_stock: + if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) and self.auto_accounting_for_stock: from erpnext.controllers.stock_controller import update_gl_entries_after items, warehouses = self.get_items_and_warehouses() update_gl_entries_after(self.posting_date, self.posting_time, diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index d0fe4f4832a..8258833254b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -717,7 +717,7 @@ class SalesInvoice(SellingController): update_outstanding_amt(self.debit_to, "Customer", self.customer, self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name) - if repost_future_gle and cint(self.update_stock) \ + if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) \ and cint(auto_accounting_for_stock): items, warehouses = self.get_items_and_warehouses() update_gl_entries_after(self.posting_date, self.posting_time, diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 2ab1575ee21..d13edc34573 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -34,7 +34,7 @@ class StockController(AccountsController): gl_entries = self.get_gl_entries(warehouse_account) make_gl_entries(gl_entries, from_repost=from_repost) - if repost_future_gle: + if (repost_future_gle or self.flags.repost_future_gle): items, warehouses = self.get_items_and_warehouses() update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items, warehouse_account, company=self.company) From 94200b1179dd6d77f2714b697b7749f0b8e325ea Mon Sep 17 00:00:00 2001 From: Marica Date: Mon, 2 Mar 2020 15:51:22 +0530 Subject: [PATCH 055/137] chore: Item Price and Product Bundle Form cleanup (#20773) * chore: Item Price and Product Bundle Form cleanup * fix: Trailing comma --- .../accounts/doctype/pricing_rule/utils.py | 6 +- .../product_bundle_item.json | 247 +++++------------- .../stock/doctype/item_price/item_price.json | 11 +- .../doctype/item_price/test_records.json | 13 +- 4 files changed, 75 insertions(+), 202 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index a2bb2ee927d..2ffa27f6d99 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -245,7 +245,7 @@ def filter_pricing_rules(args, pricing_rules, doc=None): def validate_quantity_and_amount_for_suggestion(args, qty, amount, item_code, transaction_type): fieldname, msg = '', '' - type_of_transaction = 'purcahse' if transaction_type == "buying" else "sale" + type_of_transaction = 'purchase' if transaction_type == 'buying' else 'sale' for field, value in {'min_qty': qty, 'min_amt': amount}.items(): if (args.get(field) and value < args.get(field) @@ -465,7 +465,7 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None): item_details.free_item_data.update(item_data) item_details.free_item_data['uom'] = pricing_rule.free_item_uom or item_data.stock_uom - item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item, + item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item, item_details.free_item_data['uom']).get("conversion_factor", 1) if item_details.get("parenttype") == 'Purchase Order': @@ -508,7 +508,7 @@ def validate_coupon_code(coupon_name): frappe.throw(_("Sorry,coupon code validity has not started")) elif coupon.valid_upto: if coupon.valid_upto < getdate(today()) : - frappe.throw(_("Sorry,coupon code validity has expired")) + frappe.throw(_("Sorry,coupon code validity has expired")) elif coupon.used>=coupon.maximum_use: frappe.throw(_("Sorry,coupon code are exhausted")) else: diff --git a/erpnext/selling/doctype/product_bundle_item/product_bundle_item.json b/erpnext/selling/doctype/product_bundle_item/product_bundle_item.json index 38f51dead49..dc071e4d65e 100644 --- a/erpnext/selling/doctype/product_bundle_item/product_bundle_item.json +++ b/erpnext/selling/doctype/product_bundle_item/product_bundle_item.json @@ -1,189 +1,76 @@ { - "allow_copy": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2013-05-23 16:55:51", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "creation": "2013-05-23 16:55:51", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "item_code", + "qty", + "description", + "rate", + "uom" + ], "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_code", - "oldfieldtype": "Link", - "options": "Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "item_code", + "fieldtype": "Link", + "in_global_search": 1, + "in_list_view": 1, + "label": "Item", + "oldfieldname": "item_code", + "oldfieldtype": "Link", + "options": "Item", + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Qty", - "length": 0, - "no_copy": 0, - "oldfieldname": "qty", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Qty", + "oldfieldname": "qty", + "oldfieldtype": "Currency", + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "oldfieldname": "description", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "300px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "description", + "fieldtype": "Text Editor", + "in_list_view": 1, + "label": "Description", + "oldfieldname": "description", + "oldfieldtype": "Text", + "print_width": "300px" + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "rate", - "fieldtype": "Float", - "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": "Rate", - "length": 0, - "no_copy": 0, - "oldfieldname": "rate", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "rate", + "fieldtype": "Float", + "hidden": 1, + "label": "Rate", + "oldfieldname": "rate", + "oldfieldtype": "Currency", + "print_hide": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "oldfieldname": "uom", - "oldfieldtype": "Link", - "options": "UOM", - "permlevel": 0, - "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, - "unique": 0 + "fieldname": "uom", + "fieldtype": "Link", + "in_list_view": 1, + "label": "UOM", + "oldfieldname": "uom", + "oldfieldtype": "Link", + "options": "UOM", + "read_only": 1 } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 1, - "image_view": 0, - "in_create": 0, - - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2017-02-20 13:24:05.633546", - "modified_by": "Administrator", - "module": "Selling", - "name": "Product Bundle Item", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "track_changes": 1, - "track_seen": 0 + ], + "idx": 1, + "istable": 1, + "links": [], + "modified": "2020-02-28 14:06:05.725655", + "modified_by": "Administrator", + "module": "Selling", + "name": "Product Bundle Item", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/stock/doctype/item_price/item_price.json b/erpnext/stock/doctype/item_price/item_price.json index 8456b584ca0..2e0ddfdaefc 100644 --- a/erpnext/stock/doctype/item_price/item_price.json +++ b/erpnext/stock/doctype/item_price/item_price.json @@ -10,7 +10,6 @@ "item_code", "uom", "packing_unit", - "min_qty", "column_break_17", "item_name", "brand", @@ -63,13 +62,6 @@ "fieldtype": "Int", "label": "Packing Unit" }, - { - "default": "1", - "fieldname": "min_qty", - "fieldtype": "Int", - "in_list_view": 1, - "label": "Minimum Qty " - }, { "fieldname": "column_break_17", "fieldtype": "Column Break" @@ -216,7 +208,7 @@ "icon": "fa fa-flag", "idx": 1, "links": [], - "modified": "2019-12-31 03:11:09.702250", + "modified": "2020-02-28 14:21:25.580331", "modified_by": "Administrator", "module": "Stock", "name": "Item Price", @@ -251,6 +243,7 @@ } ], "quick_entry": 1, + "sort_field": "modified", "sort_order": "ASC", "title_field": "item_name", "track_changes": 1 diff --git a/erpnext/stock/doctype/item_price/test_records.json b/erpnext/stock/doctype/item_price/test_records.json index 473bacb3c33..0a3d7e81985 100644 --- a/erpnext/stock/doctype/item_price/test_records.json +++ b/erpnext/stock/doctype/item_price/test_records.json @@ -4,7 +4,6 @@ "item_code": "_Test Item", "price_list": "_Test Price List", "price_list_rate": 100, - "min_qty": 2, "valid_from": "2017-04-18", "valid_upto": "2017-04-26" }, @@ -12,8 +11,7 @@ "doctype": "Item Price", "item_code": "_Test Item", "price_list": "_Test Price List Rest of the World", - "price_list_rate": 10, - "min_qty": 5 + "price_list_rate": 10 }, { "doctype": "Item Price", @@ -22,7 +20,6 @@ "price_list_rate": 20, "valid_from": "2017-04-18", "valid_upto": "2017-04-26", - "min_qty": 7, "customer": "_Test Customer", "uom": "_Test UOM" }, @@ -31,19 +28,15 @@ "item_code": "_Test Item Home Desktop 100", "price_list": "_Test Price List", "price_list_rate": 1000, - "min_qty" : 10, "valid_from": "2017-04-10", - "valid_upto": "2017-04-17", - "min_qty": 2 + "valid_upto": "2017-04-17" }, { "doctype": "Item Price", "item_code": "_Test Item Home Desktop Manufactured", "price_list": "_Test Price List", "price_list_rate": 1000, - "min_qty" : 10, "valid_from": "2017-04-10", - "valid_upto": "2017-04-17", - "min_qty": 2 + "valid_upto": "2017-04-17" } ] From acd93b3bd142364661b2065af8cde00c53136a47 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Mon, 2 Mar 2020 18:05:59 +0530 Subject: [PATCH 056/137] fix: use system language to translate strings (#20792) --- .../connectors/woocommerce_connection.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py index 28c2ab9e545..4422d23e380 100644 --- a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py +++ b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py @@ -47,11 +47,12 @@ def _order(*args, **kwargs): return "success" if event == "created": + sys_lang = frappe.get_single("System Settings").language or 'en' raw_billing_data = order.get("billing") customer_name = raw_billing_data.get("first_name") + " " + raw_billing_data.get("last_name") link_customer_and_address(raw_billing_data, customer_name) - link_items(order.get("line_items"), woocommerce_settings) - create_sales_order(order, woocommerce_settings, customer_name) + link_items(order.get("line_items"), woocommerce_settings, sys_lang) + create_sales_order(order, woocommerce_settings, customer_name, sys_lang) def link_customer_and_address(raw_billing_data, customer_name): customer_woo_com_email = raw_billing_data.get("email") @@ -100,7 +101,7 @@ def link_customer_and_address(raw_billing_data, customer_name): frappe.rename_doc("Address", old_address_title, new_address_title) -def link_items(items_list, woocommerce_settings): +def link_items(items_list, woocommerce_settings, sys_lang): for item_data in items_list: item_woo_com_id = item_data.get("product_id") @@ -112,14 +113,14 @@ def link_items(items_list, woocommerce_settings): item = frappe.new_doc("Item") item.item_name = item_data.get("name") - item.item_code = _("woocommerce - {0}").format(item_data.get("product_id")) + item.item_code = _("woocommerce - {0}", sys_lang).format(item_data.get("product_id")) item.woocommerce_id = item_data.get("product_id") - item.item_group = _("WooCommerce Products") - item.stock_uom = woocommerce_settings.uom or _("Nos") + item.item_group = _("WooCommerce Products", sys_lang) + item.stock_uom = woocommerce_settings.uom or _("Nos", sys_lang) item.flags.ignore_mandatory = True item.save() -def create_sales_order(order, woocommerce_settings, customer_name): +def create_sales_order(order, woocommerce_settings, customer_name, sys_lang): new_sales_order = frappe.new_doc("Sales Order") new_sales_order.customer = customer_name @@ -133,14 +134,14 @@ def create_sales_order(order, woocommerce_settings, customer_name): new_sales_order.company = woocommerce_settings.company - set_items_in_sales_order(new_sales_order, woocommerce_settings, order) + set_items_in_sales_order(new_sales_order, woocommerce_settings, order, sys_lang) new_sales_order.flags.ignore_mandatory = True new_sales_order.insert() new_sales_order.submit() frappe.db.commit() -def set_items_in_sales_order(new_sales_order, woocommerce_settings, order): +def set_items_in_sales_order(new_sales_order, woocommerce_settings, order, sys_lang): company_abbr = frappe.db.get_value('Company', woocommerce_settings.company, 'abbr') for item in order.get("line_items"): @@ -154,10 +155,10 @@ def set_items_in_sales_order(new_sales_order, woocommerce_settings, order): "item_name": found_item.item_name, "description": found_item.item_name, "delivery_date": new_sales_order.delivery_date, - "uom": woocommerce_settings.uom or _("Nos"), + "uom": woocommerce_settings.uom or _("Nos", sys_lang), "qty": item.get("quantity"), "rate": item.get("price"), - "warehouse": woocommerce_settings.warehouse or _("Stores - {0}").format(company_abbr) + "warehouse": woocommerce_settings.warehouse or _("Stores - {0}", sys_lang).format(company_abbr) }) add_tax_details(new_sales_order, ordered_items_tax, "Ordered Item tax", woocommerce_settings.tax_account) From 6a734ecd34e45a3c096d5e590ad1d33c441ba400 Mon Sep 17 00:00:00 2001 From: Prssanna Desai Date: Mon, 2 Mar 2020 18:06:21 +0530 Subject: [PATCH 057/137] fix: use get all instead of get list to fetch item attributes (#20793) --- erpnext/portal/product_configurator/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py index ce507a39486..327a128068f 100644 --- a/erpnext/portal/product_configurator/utils.py +++ b/erpnext/portal/product_configurator/utils.py @@ -188,7 +188,9 @@ def get_attributes_and_values(item_code): def get_numeric_values(): attribute_values_list = [] - numeric_attributes = frappe.get_list("Item Attribute", fields=['name', 'from_range', 'to_range', 'increment'], filters={"numeric_values": 1}) + numeric_attributes = frappe.db.get_all("Item Attribute", + fields=['name', 'from_range', 'to_range', 'increment'], + filters={"numeric_values": 1}) for attribute in numeric_attributes: from_range = attribute["from_range"] to_range = attribute['to_range'] + attribute['increment'] From d7839eb8acde1f0238aa8db74adda442eaaa369f Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 2 Mar 2020 18:09:24 +0530 Subject: [PATCH 058/137] fix: Total amount not displayed in Journal Entry (#20795) * fix: Total amount not displayed in Journal Entry * fix: Update paid_to_received field * fix: set total amount Co-authored-by: Nabin Hait --- erpnext/accounts/doctype/journal_entry/journal_entry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 428b9acd150..04c5c9ec679 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -459,8 +459,7 @@ class JournalEntry(AccountsController): for d in self.get('accounts'): if d.party_type in ['Customer', 'Supplier'] and d.party: if not pay_to_recd_from: - pay_to_recd_from = frappe.db.get_value(d.party_type, d.party, - "customer_name" if d.party_type=="Customer" else "supplier_name") + pay_to_recd_from = d.party if pay_to_recd_from and pay_to_recd_from == d.party: party_amount += (d.debit_in_account_currency or d.credit_in_account_currency) @@ -471,7 +470,8 @@ class JournalEntry(AccountsController): bank_account_currency = d.account_currency if pay_to_recd_from: - self.pay_to_recd_from = pay_to_recd_from + self.pay_to_recd_from = frappe.db.get_value(d.party_type, pay_to_recd_from, + "customer_name" if d.party_type=="Customer" else "supplier_name") if bank_amount: total_amount = bank_amount currency = bank_account_currency From 7766530afcd30641de2d7497e5a1465f407ea2e1 Mon Sep 17 00:00:00 2001 From: Priyanka Gangar <59438065+0925-pinka@users.noreply.github.com> Date: Mon, 2 Mar 2020 19:24:14 +0530 Subject: [PATCH 059/137] fix: fetch sales person name (#20801) * fix: fetch sales person name * Update sales_person.js Co-authored-by: pinka0925 <44537026+pinka0925@users.noreply.github.com> Co-authored-by: Nabin Hait --- erpnext/setup/doctype/sales_person/sales_person.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/setup/doctype/sales_person/sales_person.js b/erpnext/setup/doctype/sales_person/sales_person.js index 9ff37fa4e83..89ca4a9dd74 100644 --- a/erpnext/setup/doctype/sales_person/sales_person.js +++ b/erpnext/setup/doctype/sales_person/sales_person.js @@ -19,6 +19,11 @@ frappe.ui.form.on('Sales Person', { } } }; + + frm.make_methods = { + 'Sales Order': () => frappe.new_doc("Sales Order") + .then(() => frm.add_child("sales_team", {"sales_person": frm.doc.name})) + } } }); From 2728590471d850dab7df1ef0e76655b4de428881 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 4 Mar 2020 10:23:49 +0530 Subject: [PATCH 060/137] fix: HSN code no visible in GST itemised sales register --- .../gst_itemised_sales_register/gst_itemised_sales_register.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py index ab523e74e67..e13f509f475 100644 --- a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py +++ b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py @@ -15,7 +15,7 @@ def execute(filters=None): dict(fieldtype='Data', label='GST Category', fieldname="gst_category", width=120), dict(fieldtype='Data', label='Export Type', fieldname="export_type", width=120), dict(fieldtype='Data', label='E-Commerce GSTIN', fieldname="ecommerce_gstin", width=130), - dict(fieldtype='Data', label='HSN Code', fieldname="hsn_code", width=120) + dict(fieldtype='Data', label='HSN Code', fieldname="gst_hsn_code", width=120) ], additional_query_columns=[ 'customer_gstin', 'billing_address_gstin', From 12cdf0fb5242a3a7de10775174d66dfa0aa8a6ad Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Thu, 5 Mar 2020 10:08:43 +0530 Subject: [PATCH 061/137] fix: use ERPNext in welcome email when default company is not set Signed-off-by: Chinmay D. Pai --- erpnext/setup/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index d1c206d8b1d..ffd5ab1e840 100644 --- a/erpnext/setup/utils.py +++ b/erpnext/setup/utils.py @@ -141,6 +141,6 @@ def insert_record(records): raise def welcome_email(): - site_name = get_default_company() - title = _("Welcome to {0}".format(site_name)) + site_name = get_default_company() or "ERPNext" + title = _("Welcome to {0}").format(site_name) return title From 1f80c8dffef3d779a32fa3e9eb12b5517cb167e7 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 5 Mar 2020 13:04:53 +0530 Subject: [PATCH 062/137] perf: improve gl entry submission (#20802) * perf: improve gl entry submission * perf: add indexes * fix: replace **kwargs with *args * fix: syntax error * fix: travis * chore: remove purchase invoice from status updater * fix: set_staus args Co-Authored-By: Nabin Hait * fix: only update status for invoices & fees * [bug][fix]: set status to object instead of variable (#20790) Co-authored-by: Nabin Hait Co-authored-by: Saurabh --- .../discounted_invoice.json | 5 +- .../discounted_invoice/discounted_invoice.py | 2 +- erpnext/accounts/doctype/gl_entry/gl_entry.py | 30 +++- .../payment_entry/test_payment_entry.py | 45 +++++- .../purchase_invoice/purchase_invoice.py | 49 +++++++ .../doctype/sales_invoice/sales_invoice.py | 128 +++++++++++------- erpnext/accounts/general_ledger.py | 5 +- erpnext/controllers/status_updater.py | 11 -- 8 files changed, 212 insertions(+), 63 deletions(-) diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json index 5c3519a1592..02b0c4d937b 100644 --- a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json +++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json @@ -18,7 +18,8 @@ "in_list_view": 1, "label": "Invoice", "options": "Sales Invoice", - "reqd": 1 + "reqd": 1, + "search_index": 1 }, { "fetch_from": "sales_invoice.customer", @@ -60,7 +61,7 @@ } ], "istable": 1, - "modified": "2019-09-26 11:05:36.016772", + "modified": "2020-02-20 16:16:20.724620", "modified_by": "Administrator", "module": "Accounts", "name": "Discounted Invoice", diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py index 93dfcc14bda..109737f7276 100644 --- a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py +++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py @@ -7,4 +7,4 @@ from __future__ import unicode_literals from frappe.model.document import Document class DiscountedInvoice(Document): - pass + pass \ No newline at end of file diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index 041e419752b..f9e4fd77148 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -232,11 +232,36 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga if bal < 0 and not on_cancel: frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal))) - # Update outstanding amt on against voucher if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]: + update_outstanding_amt_in_ref(against_voucher, against_voucher_type, bal) + +def update_outstanding_amt_in_ref(against_voucher, against_voucher_type, bal): + data = [] + # Update outstanding amt on against voucher + if against_voucher_type == "Fees": ref_doc = frappe.get_doc(against_voucher_type, against_voucher) ref_doc.db_set('outstanding_amount', bal) ref_doc.set_status(update=True) + return + elif against_voucher_type == "Purchase Invoice": + from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_status + data = frappe.db.get_value(against_voucher_type, against_voucher, + ["name as purchase_invoice", "outstanding_amount", + "is_return", "due_date", "docstatus"]) + elif against_voucher_type == "Sales Invoice": + from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_status + data = frappe.db.get_value(against_voucher_type, against_voucher, + ["name as sales_invoice", "outstanding_amount", "is_discounted", + "is_return", "due_date", "docstatus"]) + + precision = frappe.get_precision(against_voucher_type, "outstanding_amount") + data = list(data) + data.append(precision) + status = get_status(data) + frappe.db.set_value(against_voucher_type, against_voucher, { + 'outstanding_amount': bal, + 'status': status + }) def validate_frozen_account(account, adv_adj=None): frozen_account = frappe.db.get_value("Account", account, "freeze_account") @@ -274,6 +299,9 @@ def update_against_account(voucher_type, voucher_no): if d.against != new_against: frappe.db.set_value("GL Entry", d.name, "against", new_against) +def on_doctype_update(): + frappe.db.add_index("GL Entry", ["against_voucher_type", "against_voucher"]) + frappe.db.add_index("GL Entry", ["voucher_type", "voucher_no"]) def rename_gle_sle_docs(): for doctype in ["GL Entry", "Stock Ledger Entry"]: diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index a7ab1754bfc..5303743d424 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -149,6 +149,49 @@ class TestPaymentEntry(unittest.TestCase): outstanding_amount = flt(frappe.db.get_value("Sales Invoice", pi.name, "outstanding_amount")) self.assertEqual(outstanding_amount, 0) + + def test_payment_against_sales_invoice_to_check_status(self): + si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", + currency="USD", conversion_rate=50) + + pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC") + pe.reference_no = "1" + pe.reference_date = "2016-01-01" + pe.target_exchange_rate = 50 + pe.insert() + pe.submit() + + outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount")) + self.assertEqual(outstanding_amount, 0) + self.assertEqual(si.status, 'Paid') + + pe.cancel() + + outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount")) + self.assertEqual(outstanding_amount, 100) + self.assertEqual(si.status, 'Unpaid') + + def test_payment_against_purchase_invoice_to_check_status(self): + pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC", + currency="USD", conversion_rate=50) + + pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank USD - _TC") + pe.reference_no = "1" + pe.reference_date = "2016-01-01" + pe.source_exchange_rate = 50 + pe.insert() + pe.submit() + + outstanding_amount = flt(frappe.db.get_value("Purchase Invoice", pi.name, "outstanding_amount")) + self.assertEqual(outstanding_amount, 0) + self.assertEqual(pi.status, 'Paid') + + pe.cancel() + + outstanding_amount = flt(frappe.db.get_value("Purchase Invoice", pi.name, "outstanding_amount")) + self.assertEqual(outstanding_amount, 100) + self.assertEqual(pi.status, 'Unpaid') + def test_payment_entry_against_ec(self): payable = frappe.get_cached_value('Company', "_Test Company", 'default_payable_account') @@ -566,4 +609,4 @@ class TestPaymentEntry(unittest.TestCase): self.assertEqual(expected_party_account_balance, party_account_balance) accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() + accounts_settings.save() \ No newline at end of file diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 518c4d36af4..754a97558b3 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -125,6 +125,27 @@ class PurchaseInvoice(BuyingController): else: self.remarks = _("No Remarks") + def set_status(self, update=False, status=None, update_modified=True): + if self.is_new(): + if self.get('amended_from'): + self.status = 'Draft' + return + + if not status: + precision = self.precision("outstanding_amount") + args = [ + self.name, + self.outstanding_amount, + self.is_return, + self.due_date, + self.docstatus, + precision + ] + self.status = get_status(args) + + if update: + self.db_set('status', self.status, update_modified = update_modified) + def set_missing_values(self, for_validate=False): if not self.credit_to: self.credit_to = get_party_account("Supplier", self.supplier, self.company) @@ -964,6 +985,34 @@ class PurchaseInvoice(BuyingController): # calculate totals again after applying TDS self.calculate_taxes_and_totals() +def get_status(*args): + purchase_invoice, outstanding_amount, is_return, due_date, docstatus, precision = args[0] + + outstanding_amount = flt(outstanding_amount, precision) + due_date = getdate(due_date) + now_date = getdate() + + if docstatus == 2: + status = "Cancelled" + elif docstatus == 1: + if outstanding_amount > 0 and due_date < now_date: + status = "Overdue" + elif outstanding_amount > 0 and due_date >= now_date: + status = "Unpaid" + #Check if outstanding amount is 0 due to debit note issued against invoice + elif outstanding_amount <= 0 and is_return == 0 and frappe.db.get_value('Purchase Invoice', {'is_return': 1, 'return_against': purchase_invoice, 'docstatus': 1}): + status = "Debit Note Issued" + elif is_return == 1: + status = "Return" + elif outstanding_amount <=0: + status = "Paid" + else: + status = "Submitted" + else: + status = "Draft" + + return status + def get_list_context(context=None): from erpnext.controllers.website_list_for_contact import get_list_context list_context = get_list_context(context) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 8258833254b..ed34127fbb3 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1211,63 +1211,84 @@ class SalesInvoice(SellingController): self.set_missing_values(for_validate = True) - def get_discounting_status(self): - status = None - if self.is_discounted: - invoice_discounting_list = frappe.db.sql(""" - select status - from `tabInvoice Discounting` id, `tabDiscounted Invoice` d - where - id.name = d.parent - and d.sales_invoice=%s - and id.docstatus=1 - and status in ('Disbursed', 'Settled') - """, self.name) - for d in invoice_discounting_list: - status = d[0] - if status == "Disbursed": - break - return status - def set_status(self, update=False, status=None, update_modified=True): if self.is_new(): if self.get('amended_from'): self.status = 'Draft' return - precision = self.precision("outstanding_amount") - outstanding_amount = flt(self.outstanding_amount, precision) - due_date = getdate(self.due_date) - nowdate = getdate() - discountng_status = self.get_discounting_status() - if not status: - if self.docstatus == 2: - status = "Cancelled" - elif self.docstatus == 1: - if outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed': - self.status = "Overdue and Discounted" - elif outstanding_amount > 0 and due_date < nowdate: - self.status = "Overdue" - elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discountng_status=='Disbursed': - self.status = "Unpaid and Discounted" - elif outstanding_amount > 0 and due_date >= nowdate: - self.status = "Unpaid" - #Check if outstanding amount is 0 due to credit note issued against invoice - elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): - self.status = "Credit Note Issued" - elif self.is_return == 1: - self.status = "Return" - elif outstanding_amount<=0: - self.status = "Paid" - else: - self.status = "Submitted" - else: - self.status = "Draft" + precision = self.precision("outstanding_amount") + args = [ + self.name, + self.outstanding_amount, + self.is_discounted, + self.is_return, + self.due_date, + self.docstatus, + precision, + ] + self.status = get_status(args) if update: self.db_set('status', self.status, update_modified = update_modified) +def get_discounting_status(sales_invoice): + status = None + + invoice_discounting_list = frappe.db.sql(""" + select status + from `tabInvoice Discounting` id, `tabDiscounted Invoice` d + where + id.name = d.parent + and d.sales_invoice=%s + and id.docstatus=1 + and status in ('Disbursed', 'Settled') + """, sales_invoice) + + for d in invoice_discounting_list: + status = d[0] + if status == "Disbursed": + break + + return status + +def get_status(*args): + sales_invoice, outstanding_amount, is_discounted, is_return, due_date, docstatus, precision = args[0] + + discounting_status = None + if is_discounted: + discounting_status = get_discounting_status(sales_invoice) + + outstanding_amount = flt(outstanding_amount, precision) + due_date = getdate(due_date) + now_date = getdate() + + if docstatus == 2: + status = "Cancelled" + elif docstatus == 1: + if outstanding_amount > 0 and due_date < now_date and is_discounted and discounting_status=='Disbursed': + status = "Overdue and Discounted" + elif outstanding_amount > 0 and due_date < now_date: + status = "Overdue" + elif outstanding_amount > 0 and due_date >= now_date and is_discounted and discounting_status=='Disbursed': + status = "Unpaid and Discounted" + elif outstanding_amount > 0 and due_date >= now_date: + status = "Unpaid" + #Check if outstanding amount is 0 due to credit note issued against invoice + elif outstanding_amount <= 0 and is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': sales_invoice, 'docstatus': 1}): + status = "Credit Note Issued" + elif is_return == 1: + status = "Return" + elif outstanding_amount <=0: + status = "Paid" + else: + status = "Submitted" + else: + status = "Draft" + + return status + def validate_inter_company_party(doctype, party, company, inter_company_reference): if not party: return @@ -1435,6 +1456,21 @@ def get_inter_company_details(doc, doctype): "company": company } +def get_internal_party(parties, link_doctype, doc): + if len(parties) == 1: + party = parties[0].name + else: + # If more than one Internal Supplier/Customer, get supplier/customer on basis of address + if doc.get('company_address') or doc.get('shipping_address'): + party = frappe.db.get_value("Dynamic Link", {"parent": doc.get('company_address') or doc.get('shipping_address'), + "parenttype": "Address", "link_doctype": link_doctype}, "link_name") + + if not party: + party = parties[0].name + else: + party = parties[0].name + + return party def validate_inter_company_transaction(doc, doctype): diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index bb1b7e392dc..6d53530321f 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -140,8 +140,11 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False): gle = frappe.get_doc(args) gle.flags.ignore_permissions = 1 gle.flags.from_repost = from_repost - gle.insert() + gle.validate() + gle.flags.ignore_permissions = True + gle.db_insert() gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost) + gle.flags.ignore_validate = True gle.submit() def validate_account_for_perpetual_inventory(gl_map): diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 8b275a64fb3..b465a106f0e 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -44,17 +44,6 @@ status_map = { ["Closed", "eval:self.status=='Closed'"], ["On Hold", "eval:self.status=='On Hold'"], ], - "Purchase Invoice": [ - ["Draft", None], - ["Submitted", "eval:self.docstatus==1"], - ["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"], - ["Return", "eval:self.is_return==1 and self.docstatus==1"], - ["Debit Note Issued", - "eval:self.outstanding_amount <= 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"], - ["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"], - ["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"], - ["Cancelled", "eval:self.docstatus==2"], - ], "Purchase Order": [ ["Draft", None], ["To Receive and Bill", "eval:self.per_received < 100 and self.per_billed < 100 and self.docstatus == 1"], From 69d3c4ff254aeeb5f9279220baf6443b447af272 Mon Sep 17 00:00:00 2001 From: Marica Date: Fri, 6 Mar 2020 10:57:43 +0530 Subject: [PATCH 063/137] fix: update_child_qty_rate() missing argument (#20839) --- erpnext/public/js/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 3f444f83879..98986f8bf1b 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -439,12 +439,13 @@ erpnext.utils.update_child_items = function(opts) { const dialog = new frappe.ui.Dialog({ title: __("Update Items"), fields: [ - {fieldtype:'Section Break', label: __('Items')}, { fieldname: "trans_items", fieldtype: "Table", + label: "Items", cannot_add_rows: cannot_add_row, in_place_edit: true, + reqd: 1, data: this.data, get_data: () => { return this.data; From 6c4cddccf6c9bec81c533aaf72865998e42de72d Mon Sep 17 00:00:00 2001 From: Saqib Date: Fri, 6 Mar 2020 11:06:41 +0530 Subject: [PATCH 064/137] fix: show uom in print formats instead of stock uom (#20844) Co-authored-by: Saqib Ansari --- .../purchase_invoice_item/purchase_invoice_item.json | 3 +-- .../selling/doctype/quotation_item/quotation_item.json | 8 ++++++-- .../doctype/sales_order_item/sales_order_item.json | 4 ++-- .../doctype/delivery_note_item/delivery_note_item.json | 6 ++++-- .../purchase_receipt_item/purchase_receipt_item.json | 4 ++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index acb0398b5c0..36bb2be3dc5 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -198,7 +198,6 @@ "fieldtype": "Link", "label": "UOM", "options": "UOM", - "print_hide": 1, "reqd": 1 }, { @@ -771,7 +770,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2019-12-04 12:23:17.046413", + "modified": "2020-03-05 14:20:17.297284", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index a299b8809ab..3ff5555e827 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2013-03-07 11:42:57", "doctype": "DocType", "document_type": "Document", @@ -163,6 +164,7 @@ "oldfieldname": "stock_uom", "oldfieldtype": "Data", "options": "UOM", + "print_hide": 1, "print_width": "100px", "read_only": 1, "width": "100px" @@ -176,7 +178,6 @@ "fieldtype": "Link", "label": "UOM", "options": "UOM", - "print_hide": 1, "reqd": 1 }, { @@ -382,6 +383,7 @@ "read_only": 1 }, { + "default": "0", "fieldname": "is_free_item", "fieldtype": "Check", "label": "Is Free Item", @@ -517,6 +519,7 @@ }, { "allow_on_submit": 1, + "default": "0", "fieldname": "page_break", "fieldtype": "Check", "label": "Page Break", @@ -574,7 +577,8 @@ ], "idx": 1, "istable": 1, - "modified": "2019-05-01 17:39:14.228141", + "links": [], + "modified": "2020-03-05 14:18:58.783751", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 317f284eff3..c95f236ebba 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -209,7 +209,6 @@ "fieldtype": "Link", "label": "UOM", "options": "UOM", - "print_hide": 1, "reqd": 1 }, { @@ -758,7 +757,8 @@ ], "idx": 1, "istable": 1, - "modified": "2019-12-11 18:06:26.238169", + "links": [], + "modified": "2020-03-05 14:20:28.085117", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index af06daeabd3..782ac84e57d 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "hash", "creation": "2013-04-22 13:15:44", "doctype": "DocType", @@ -180,6 +181,7 @@ "oldfieldname": "stock_uom", "oldfieldtype": "Data", "options": "UOM", + "print_hide": 1, "print_width": "50px", "read_only": 1, "reqd": 1, @@ -195,7 +197,6 @@ "in_list_view": 1, "label": "UOM", "options": "UOM", - "print_hide": 1, "reqd": 1 }, { @@ -702,7 +703,8 @@ ], "idx": 1, "istable": 1, - "modified": "2019-05-25 22:08:27.452734", + "links": [], + "modified": "2020-03-05 14:18:33.131672", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 16ec8db335c..d5cf4cadb14 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -222,7 +222,6 @@ "oldfieldname": "uom", "oldfieldtype": "Link", "options": "UOM", - "print_hide": 1, "print_width": "100px", "reqd": 1, "width": "100px" @@ -823,7 +822,8 @@ ], "idx": 1, "istable": 1, - "modified": "2019-10-14 16:03:25.499557", + "links": [], + "modified": "2020-03-05 14:19:48.799370", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", From 875e0f5fb23589f2e44ffbf344a1f01cf37d1f7b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 9 Mar 2020 08:06:07 +0530 Subject: [PATCH 065/137] fix: Acccounting Dimension disappearing in first row after refresh --- erpnext/public/js/utils/dimension_tree_filter.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js index 7abe4a7aab1..8b6de0f5179 100644 --- a/erpnext/public/js/utils/dimension_tree_filter.js +++ b/erpnext/public/js/utils/dimension_tree_filter.js @@ -35,11 +35,13 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => { } } - if (frm.doc.items && frm.doc.items.length) { + if (frm.doc.items && frm.doc.items.length && frm.doc.docstatus === 0 + && (!frm.doc.items[0][dimension['fieldname']])) { frm.doc.items[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']]; } - if (frm.doc.accounts && frm.doc.accounts.length) { + if (frm.doc.accounts && frm.doc.accounts.length && frm.doc.docstatus === 0 + && (!frm.doc.items[0][dimension['fieldname']])) { frm.doc.accounts[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']]; } } From 2f2cef6c5f8574b5e928280436aec0fb80b13588 Mon Sep 17 00:00:00 2001 From: Marica Date: Mon, 9 Mar 2020 18:07:55 +0530 Subject: [PATCH 066/137] fix: ModuleNotFoundError on Turkey Company setup (#20854) --- erpnext/regional/turkey/setup.py | 4 ++++ erpnext/setup/doctype/company/company.py | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 erpnext/regional/turkey/setup.py diff --git a/erpnext/regional/turkey/setup.py b/erpnext/regional/turkey/setup.py new file mode 100644 index 00000000000..ebf3b2bee1f --- /dev/null +++ b/erpnext/regional/turkey/setup.py @@ -0,0 +1,4 @@ +from __future__ import unicode_literals + +def setup(company=None, patch=True): + pass \ No newline at end of file diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index ff3515485c4..c3fd3566578 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -416,8 +416,13 @@ def install_country_fixtures(company): company_doc = frappe.get_doc("Company", company) path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(company_doc.country)) if os.path.exists(path.encode("utf-8")): - frappe.get_attr("erpnext.regional.{0}.setup.setup" - .format(frappe.scrub(company_doc.country)))(company_doc, False) + try: + module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(company_doc.country)) + frappe.get_attr(module_name)(company_doc, False) + except Exception as e: + frappe.log_error(str(e), frappe.get_traceback()) + frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(company_doc.country))) + def update_company_current_month_sales(company): current_month_year = formatdate(today(), "MM-yyyy") From d08cff9efc35892980496b11a913a1ab836e64e1 Mon Sep 17 00:00:00 2001 From: Marica Date: Mon, 9 Mar 2020 18:13:38 +0530 Subject: [PATCH 067/137] fix: Validate Serial No/Batch No against unserialized Item in Stock Reconciliation (#20859) --- .../stock/doctype/stock_reconciliation/stock_reconciliation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index ca2741ccfba..afa239466b5 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -190,6 +190,9 @@ class StockReconciliation(StockController): has_serial_no = True self.get_sle_for_serialized_items(row, sl_entries) else: + if row.serial_no or row.batch_no: + frappe.throw(_("Row #{0}: Item {1} is not a Serialized/Batched Item. It cannot have a Serial No/Batch No against it.") \ + .format(row.idx, frappe.bold(row.item_code))) previous_sle = get_previous_sle({ "item_code": row.item_code, "warehouse": row.warehouse, From b607963fba27e92224ce8a40b32443d33717643f Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 9 Mar 2020 18:30:42 +0530 Subject: [PATCH 068/137] fix: [pos] customer group filter resets on syncing offline invoices (#20874) --- erpnext/accounts/doctype/sales_invoice/pos.py | 9 ++++++--- erpnext/accounts/page/pos/pos.js | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 749816f7814..c0e128567f9 100755 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -207,7 +207,7 @@ def get_customers_list(pos_profile={}): if pos_profile.get('customer_groups'): # Get customers based on the customer groups defined in the POS profile for d in pos_profile.get('customer_groups'): - customer_groups.extend([d.name for d in get_child_nodes('Customer Group', d.customer_group)]) + customer_groups.extend([d.get('name') for d in get_child_nodes('Customer Group', d.get('customer_group'))]) cond = "customer_group in (%s)" % (', '.join(['%s'] * len(customer_groups))) return frappe.db.sql(""" select name, customer_name, customer_group, @@ -387,7 +387,9 @@ def get_pricing_rule_data(doc): @frappe.whitelist() -def make_invoice(doc_list={}, email_queue_list={}, customers_list={}): +def make_invoice(pos_profile, doc_list={}, email_queue_list={}, customers_list={}): + import json + if isinstance(doc_list, string_types): doc_list = json.loads(doc_list) @@ -421,7 +423,8 @@ def make_invoice(doc_list={}, email_queue_list={}, customers_list={}): name_list.append(name) email_queue = make_email_queue(email_queue_list) - customers = get_customers_list() + pos_profile = json.loads(pos_profile) + customers = get_customers_list(pos_profile) return { 'invoice': name_list, 'email_queue': email_queue, diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 8dc00f3f218..24fcb41a5db 100755 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -1769,6 +1769,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice", freeze: true, args: { + pos_profile: me.pos_profile_data, doc_list: me.si_docs, email_queue_list: me.email_queue_list, customers_list: me.customers_list From 0317576434c948ebbeb03018e7d56b843dfcd6fd Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 9 Mar 2020 22:38:41 +0530 Subject: [PATCH 069/137] fix: HSN code not visible in GST Itemised Purchase register --- .../item_wise_purchase_register.py | 4 ++-- .../gst_itemised_purchase_register.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 4523f66deb4..11f4e0d4e85 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -54,8 +54,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum 'description': d.description, 'invoice': d.parent, 'posting_date': d.posting_date, - 'customer': d.supplier, - 'customer_name': d.supplier_name + 'supplier': d.supplier, + 'supplier_name': d.supplier_name } if additional_query_columns: diff --git a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py index 3ce2547b20f..b5948f9952d 100644 --- a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py +++ b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py @@ -13,9 +13,9 @@ def execute(filters=None): dict(fieldtype='Data', label='GST Category', fieldname="gst_category", width=120), dict(fieldtype='Data', label='Export Type', fieldname="export_type", width=120), dict(fieldtype='Data', label='E-Commerce GSTIN', fieldname="ecommerce_gstin", width=130), - dict(fieldtype='Data', label='HSN Code', fieldname="hsn_code", width=120), - dict(fieldtype='Data', label='Supplier Invoice No', fieldname="supplier_invoice_no", width=120), - dict(fieldtype='Date', label='Supplier Invoice Date', fieldname="supplier_invoice_date", width=100) + dict(fieldtype='Data', label='HSN Code', fieldname="gst_hsn_code", width=120), + dict(fieldtype='Data', label='Supplier Invoice No', fieldname="bill_no", width=120), + dict(fieldtype='Date', label='Supplier Invoice Date', fieldname="bill_date", width=100) ], additional_query_columns=[ 'supplier_gstin', 'company_gstin', From ee003495f6470c88fc70192e60def6de07370fed Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 10 Mar 2020 10:36:05 +0530 Subject: [PATCH 070/137] fix: Get invoice details only if invoice is selected --- erpnext/accounts/doctype/c_form/c_form.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/c_form/c_form.js b/erpnext/accounts/doctype/c_form/c_form.js index 3d0fc0a42ce..846408ff244 100644 --- a/erpnext/accounts/doctype/c_form/c_form.js +++ b/erpnext/accounts/doctype/c_form/c_form.js @@ -32,10 +32,12 @@ frappe.ui.form.on('C-Form Invoice Detail', { invoice_no(frm, cdt, cdn) { let d = frappe.get_doc(cdt, cdn); - frm.call('get_invoice_details', { - invoice_no: d.invoice_no - }).then(r => { - frappe.model.set_value(cdt, cdn, r.message); - }); + if (d.invoice_no) { + frm.call('get_invoice_details', { + invoice_no: d.invoice_no + }).then(r => { + frappe.model.set_value(cdt, cdn, r.message); + }); + } } }); From 97dfe2ac32aa38b0578476b84c278e74908138aa Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Mon, 16 Mar 2020 13:47:47 +0530 Subject: [PATCH 071/137] fix: local variable 'benefit_amount' referenced before assignment (#20948) --- .../employee_benefit_application/employee_benefit_application.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py b/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py index fea4246d646..feaa92590a3 100644 --- a/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py +++ b/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py @@ -190,6 +190,7 @@ def get_benefit_component_amount(employee, start_date, end_date, salary_componen component_max_benefit, depends_on_payment_days = frappe.db.get_value("Salary Component", salary_component, ["max_benefit_amount", "depends_on_payment_days"]) + benefit_amount = 0 if benefit_application: benefit_amount = frappe.db.get_value("Employee Benefit Application Detail", {"parent": benefit_application[0][0], "earning_component": salary_component}, "amount") From e2a31f221a0c0977bab5623d3b574eeee402bbfc Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 16 Mar 2020 15:36:10 +0530 Subject: [PATCH 072/137] fix: Multiple fixes for travis (#20950) --- erpnext/accounts/doctype/gl_entry/gl_entry.py | 32 ++------ .../payment_entry/test_payment_entry.py | 24 +++--- .../purchase_invoice/purchase_invoice.py | 52 +------------ erpnext/accounts/doctype/sales_invoice/pos.py | 5 +- .../doctype/sales_invoice/sales_invoice.py | 78 ++++++++----------- .../sales_invoice/test_sales_invoice.py | 10 +-- erpnext/accounts/general_ledger.py | 5 +- erpnext/controllers/status_updater.py | 11 +++ erpnext/setup/doctype/company/test_company.py | 2 +- erpnext/stock/doctype/item/item.py | 11 ++- .../purchase_receipt/test_purchase_receipt.py | 10 ++- 11 files changed, 89 insertions(+), 151 deletions(-) diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index f9e4fd77148..512e348c8bf 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -233,35 +233,13 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal))) if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]: - update_outstanding_amt_in_ref(against_voucher, against_voucher_type, bal) - -def update_outstanding_amt_in_ref(against_voucher, against_voucher_type, bal): - data = [] - # Update outstanding amt on against voucher - if against_voucher_type == "Fees": ref_doc = frappe.get_doc(against_voucher_type, against_voucher) - ref_doc.db_set('outstanding_amount', bal) - ref_doc.set_status(update=True) - return - elif against_voucher_type == "Purchase Invoice": - from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_status - data = frappe.db.get_value(against_voucher_type, against_voucher, - ["name as purchase_invoice", "outstanding_amount", - "is_return", "due_date", "docstatus"]) - elif against_voucher_type == "Sales Invoice": - from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_status - data = frappe.db.get_value(against_voucher_type, against_voucher, - ["name as sales_invoice", "outstanding_amount", "is_discounted", - "is_return", "due_date", "docstatus"]) - precision = frappe.get_precision(against_voucher_type, "outstanding_amount") - data = list(data) - data.append(precision) - status = get_status(data) - frappe.db.set_value(against_voucher_type, against_voucher, { - 'outstanding_amount': bal, - 'status': status - }) + # Didn't use db_set for optimisation purpose + ref_doc.outstanding_amount = bal + frappe.db.set_value(against_voucher_type, against_voucher, 'outstanding_amount', bal) + + ref_doc.set_status(update=True) def validate_frozen_account(account, adv_adj=None): frozen_account = frappe.db.get_value("Account", account, "freeze_account") diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 5303743d424..a25e0e32c86 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -161,15 +161,15 @@ class TestPaymentEntry(unittest.TestCase): pe.insert() pe.submit() - outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount")) - self.assertEqual(outstanding_amount, 0) - self.assertEqual(si.status, 'Paid') + outstanding_amount, status = frappe.db.get_value("Sales Invoice", si.name, ["outstanding_amount", "status"]) + self.assertEqual(flt(outstanding_amount), 0) + self.assertEqual(status, 'Paid') pe.cancel() - outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount")) - self.assertEqual(outstanding_amount, 100) - self.assertEqual(si.status, 'Unpaid') + outstanding_amount, status = frappe.db.get_value("Sales Invoice", si.name, ["outstanding_amount", "status"]) + self.assertEqual(flt(outstanding_amount), 100) + self.assertEqual(status, 'Unpaid') def test_payment_against_purchase_invoice_to_check_status(self): pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC", @@ -182,15 +182,15 @@ class TestPaymentEntry(unittest.TestCase): pe.insert() pe.submit() - outstanding_amount = flt(frappe.db.get_value("Purchase Invoice", pi.name, "outstanding_amount")) - self.assertEqual(outstanding_amount, 0) - self.assertEqual(pi.status, 'Paid') + outstanding_amount, status = frappe.db.get_value("Purchase Invoice", pi.name, ["outstanding_amount", "status"]) + self.assertEqual(flt(outstanding_amount), 0) + self.assertEqual(status, 'Paid') pe.cancel() - outstanding_amount = flt(frappe.db.get_value("Purchase Invoice", pi.name, "outstanding_amount")) - self.assertEqual(outstanding_amount, 100) - self.assertEqual(pi.status, 'Unpaid') + outstanding_amount, status = frappe.db.get_value("Purchase Invoice", pi.name, ["outstanding_amount", "status"]) + self.assertEqual(flt(outstanding_amount), 250) + self.assertEqual(status, 'Unpaid') def test_payment_entry_against_ec(self): diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 754a97558b3..698c2ab333d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -125,27 +125,6 @@ class PurchaseInvoice(BuyingController): else: self.remarks = _("No Remarks") - def set_status(self, update=False, status=None, update_modified=True): - if self.is_new(): - if self.get('amended_from'): - self.status = 'Draft' - return - - if not status: - precision = self.precision("outstanding_amount") - args = [ - self.name, - self.outstanding_amount, - self.is_return, - self.due_date, - self.docstatus, - precision - ] - self.status = get_status(args) - - if update: - self.db_set('status', self.status, update_modified = update_modified) - def set_missing_values(self, for_validate=False): if not self.credit_to: self.credit_to = get_party_account("Supplier", self.supplier, self.company) @@ -985,34 +964,6 @@ class PurchaseInvoice(BuyingController): # calculate totals again after applying TDS self.calculate_taxes_and_totals() -def get_status(*args): - purchase_invoice, outstanding_amount, is_return, due_date, docstatus, precision = args[0] - - outstanding_amount = flt(outstanding_amount, precision) - due_date = getdate(due_date) - now_date = getdate() - - if docstatus == 2: - status = "Cancelled" - elif docstatus == 1: - if outstanding_amount > 0 and due_date < now_date: - status = "Overdue" - elif outstanding_amount > 0 and due_date >= now_date: - status = "Unpaid" - #Check if outstanding amount is 0 due to debit note issued against invoice - elif outstanding_amount <= 0 and is_return == 0 and frappe.db.get_value('Purchase Invoice', {'is_return': 1, 'return_against': purchase_invoice, 'docstatus': 1}): - status = "Debit Note Issued" - elif is_return == 1: - status = "Return" - elif outstanding_amount <=0: - status = "Paid" - else: - status = "Submitted" - else: - status = "Draft" - - return status - def get_list_context(context=None): from erpnext.controllers.website_list_for_contact import get_list_context list_context = get_list_context(context) @@ -1073,3 +1024,6 @@ def block_invoice(name, release_date, hold_comment=None): def make_inter_company_sales_invoice(source_name, target_doc=None): from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction return make_inter_company_transaction("Purchase Invoice", source_name, target_doc) + +def on_doctype_update(): + frappe.db.add_index("Purchase Invoice", ["supplier", "is_return", "return_against"]) \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index c0e128567f9..16e918cc728 100755 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -423,7 +423,10 @@ def make_invoice(pos_profile, doc_list={}, email_queue_list={}, customers_list={ name_list.append(name) email_queue = make_email_queue(email_queue_list) - pos_profile = json.loads(pos_profile) + + if isinstance(pos_profile, string_types): + pos_profile = json.loads(pos_profile) + customers = get_customers_list(pos_profile) return { 'invoice': name_list, diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index ed34127fbb3..fcddab40b8f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1217,18 +1217,38 @@ class SalesInvoice(SellingController): self.status = 'Draft' return + precision = self.precision("outstanding_amount") + outstanding_amount = flt(self.outstanding_amount, precision) + due_date = getdate(self.due_date) + nowdate = getdate() + + discounting_status = None + if self.is_discounted: + discountng_status = get_discounting_status(self.name) + if not status: - precision = self.precision("outstanding_amount") - args = [ - self.name, - self.outstanding_amount, - self.is_discounted, - self.is_return, - self.due_date, - self.docstatus, - precision, - ] - self.status = get_status(args) + if self.docstatus == 2: + status = "Cancelled" + elif self.docstatus == 1: + if outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed': + self.status = "Overdue and Discounted" + elif outstanding_amount > 0 and due_date < nowdate: + self.status = "Overdue" + elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discountng_status=='Disbursed': + self.status = "Unpaid and Discounted" + elif outstanding_amount > 0 and due_date >= nowdate: + self.status = "Unpaid" + #Check if outstanding amount is 0 due to credit note issued against invoice + elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): + self.status = "Credit Note Issued" + elif self.is_return == 1: + self.status = "Return" + elif outstanding_amount<=0: + self.status = "Paid" + else: + self.status = "Submitted" + else: + self.status = "Draft" if update: self.db_set('status', self.status, update_modified = update_modified) @@ -1253,42 +1273,6 @@ def get_discounting_status(sales_invoice): return status -def get_status(*args): - sales_invoice, outstanding_amount, is_discounted, is_return, due_date, docstatus, precision = args[0] - - discounting_status = None - if is_discounted: - discounting_status = get_discounting_status(sales_invoice) - - outstanding_amount = flt(outstanding_amount, precision) - due_date = getdate(due_date) - now_date = getdate() - - if docstatus == 2: - status = "Cancelled" - elif docstatus == 1: - if outstanding_amount > 0 and due_date < now_date and is_discounted and discounting_status=='Disbursed': - status = "Overdue and Discounted" - elif outstanding_amount > 0 and due_date < now_date: - status = "Overdue" - elif outstanding_amount > 0 and due_date >= now_date and is_discounted and discounting_status=='Disbursed': - status = "Unpaid and Discounted" - elif outstanding_amount > 0 and due_date >= now_date: - status = "Unpaid" - #Check if outstanding amount is 0 due to credit note issued against invoice - elif outstanding_amount <= 0 and is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': sales_invoice, 'docstatus': 1}): - status = "Credit Note Issued" - elif is_return == 1: - status = "Return" - elif outstanding_amount <=0: - status = "Paid" - else: - status = "Submitted" - else: - status = "Draft" - - return status - def validate_inter_company_party(doctype, party, company, inter_company_reference): if not party: return diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index a2a47b3a19c..267e52a477b 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -728,7 +728,7 @@ class TestSalesInvoice(unittest.TestCase): def test_make_pos_invoice(self): from erpnext.accounts.doctype.sales_invoice.pos import make_invoice - make_pos_profile() + pos_profile = make_pos_profile() pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1") pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True) @@ -744,7 +744,7 @@ class TestSalesInvoice(unittest.TestCase): pos.append("taxes", tax) invoice_data = [{'09052016142': pos}] - si = make_invoice(invoice_data).get('invoice') + si = make_invoice(pos_profile, invoice_data).get('invoice') self.assertEqual(si[0], '09052016142') sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': '09052016142', 'docstatus': 1}) @@ -762,7 +762,7 @@ class TestSalesInvoice(unittest.TestCase): if allow_negative_stock: frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 0) - make_pos_profile() + pos_profile = make_pos_profile() timestamp = cint(time.time()) item = make_item("_Test POS Item") @@ -776,7 +776,7 @@ class TestSalesInvoice(unittest.TestCase): {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 330}] invoice_data = [{timestamp: pos}] - si = make_invoice(invoice_data).get('invoice') + si = make_invoice(pos_profile, invoice_data).get('invoice') self.assertEqual(si[0], timestamp) sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': timestamp}) @@ -785,7 +785,7 @@ class TestSalesInvoice(unittest.TestCase): timestamp = cint(time.time()) pos["offline_pos_name"] = timestamp invoice_data = [{timestamp: pos}] - si1 = make_invoice(invoice_data).get('invoice') + si1 = make_invoice(pos_profile, invoice_data).get('invoice') self.assertEqual(si1[0], timestamp) sales_invoice1 = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': timestamp}) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 6d53530321f..5ba455c1315 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -136,12 +136,11 @@ def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False): def make_entry(args, adv_adj, update_outstanding, from_repost=False): - args.update({"doctype": "GL Entry"}) - gle = frappe.get_doc(args) + gle = frappe.new_doc("GL Entry") + gle.update(args) gle.flags.ignore_permissions = 1 gle.flags.from_repost = from_repost gle.validate() - gle.flags.ignore_permissions = True gle.db_insert() gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost) gle.flags.ignore_validate = True diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index b465a106f0e..4d0520abc81 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -69,6 +69,17 @@ status_map = { ["Cancelled", "eval:self.docstatus==2"], ["Closed", "eval:self.status=='Closed'"], ], + "Purchase Invoice": [ + ["Draft", None], + ["Submitted", "eval:self.docstatus==1"], + ["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"], + ["Return", "eval:self.is_return==1 and self.docstatus==1"], + ["Debit Note Issued", + "eval:self.outstanding_amount <= 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"], + ["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"], + ["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"], + ["Cancelled", "eval:self.docstatus==2"], + ], "Material Request": [ ["Draft", None], ["Stopped", "eval:self.status == 'Stopped'"], diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py index 524f3eb5b17..fe13d63955f 100644 --- a/erpnext/setup/doctype/company/test_company.py +++ b/erpnext/setup/doctype/company/test_company.py @@ -9,7 +9,7 @@ from frappe import _ from frappe.utils import random_string from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import get_charts_for_country -test_ignore = ["Account", "Cost Center", "Payment Terms Template", "Salary Component"] +test_ignore = ["Account", "Cost Center", "Payment Terms Template", "Salary Component", "Warehouse"] test_dependencies = ["Fiscal Year"] test_records = frappe.get_test_records('Company') diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index d2e04914017..cb0eb406df6 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -183,12 +183,17 @@ class Item(WebsiteGenerator): # default warehouse, or Stores for default in self.item_defaults or [frappe._dict({'company': frappe.defaults.get_defaults().company})]: default_warehouse = (default.default_warehouse - or frappe.db.get_single_value('Stock Settings', 'default_warehouse') - or frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')})) + or frappe.db.get_single_value('Stock Settings', 'default_warehouse')) + if default_warehouse: + warehouse_company = frappe.db.get_value("Warehouse", default_warehouse, "company") + + if not default_warehouse or warehouse_company != default.company: + default_warehouse = frappe.db.get_value('Warehouse', + {'warehouse_name': _('Stores'), 'company': default.company}) if default_warehouse: stock_entry = make_stock_entry(item_code=self.name, target=default_warehouse, qty=self.opening_stock, - rate=self.valuation_rate, company=default.company) + rate=self.valuation_rate, company=default.company) stock_entry.add_comment("Comment", _("Opening Stock")) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 7ea84e99131..6e19b71cac8 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -53,7 +53,7 @@ class TestPurchaseReceipt(unittest.TestCase): self.assertFalse(get_gl_entries("Purchase Receipt", pr.name)) def test_batched_serial_no_purchase(self): - item = frappe.get_doc("Item", { 'item_name': 'Batched Serialized Item' }) + item = frappe.db.exists("Item", {'item_name': 'Batched Serialized Item'}) if not item: item = create_item("Batched Serialized Item") item.has_batch_no = 1 @@ -62,6 +62,8 @@ class TestPurchaseReceipt(unittest.TestCase): item.batch_number_series = "BS-BATCH-.##" item.serial_no_series = "BS-.####" item.save() + else: + item = frappe.get_doc("Item", {'item_name': 'Batched Serialized Item'}) pr = make_purchase_receipt(item_code=item.name, qty=5, rate=500) @@ -302,6 +304,8 @@ class TestPurchaseReceipt(unittest.TestCase): self.assertEqual(serial_no, frappe.db.get_value("Serial No", {"purchase_document_type": "Purchase Receipt", "purchase_document_no": pr_doc.name}, "name")) + pr_doc.cancel() + item_code = "Test Auto Created Serial No" if not frappe.db.exists("Item", item_code): item = make_item(item_code, dict(has_serial_no=1, serial_no_series="KLJL.###")) @@ -316,9 +320,9 @@ class TestPurchaseReceipt(unittest.TestCase): from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note - item_code = frappe.db.get_value('Item', {'has_serial_no': 1, 'is_fixed_asset': 0}) + item_code = frappe.db.get_value('Item', {'has_serial_no': 1, 'is_fixed_asset': 0, "has_batch_no": 0}) if not item_code: - item = make_item("Test Serial Item 1", dict(has_serial_no=1)) + item = make_item("Test Serial Item 1", dict(has_serial_no=1, has_batch_no=0)) item_code = item.name serial_no = random_string(5) From cd71114c1575756eccee1ddae9d4c160d06b9396 Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Mon, 16 Mar 2020 11:14:32 +0100 Subject: [PATCH 073/137] fix(accounts): add account_type and tax_rate to some VAT accounts (#20941) * Add account_type and tax rate to some VAT accounts * fix indentation --- ..._kontenplan_SKR04_with_account_number.json | 142 ++++++++++-------- 1 file changed, 76 insertions(+), 66 deletions(-) diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json index adfa9f89e23..275374a4b70 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json @@ -406,11 +406,11 @@ "is_group": 1, "Bewertungskorrektur zu Forderungen aus Lieferungen und Leistungen": { "account_number": "9960" - }, - "Debitoren": { - "is_group": 1, - "account_number": "10000" - }, + }, + "Debitoren": { + "is_group": 1, + "account_number": "10000" + }, "Forderungen aus Lieferungen und Leistungen": { "account_number": "1200", "account_type": "Receivable" @@ -663,16 +663,22 @@ "account_number": "1400" }, "Abziehbare Vorsteuer 7 %": { - "account_number": "1401" + "account_number": "1401", + "account_type": "Tax", + "tax_rate": 7.0 }, "Abziehbare Vorsteuer aus innergem. Erwerb": { "account_number": "1402" }, "Abziehbare Vorsteuer aus innergem. Erwerb 19%": { - "account_number": "1404" + "account_number": "1404", + "account_type": "Tax", + "tax_rate": 19.0 }, "Abziehbare Vorsteuer 19 %": { - "account_number": "1406" + "account_number": "1406", + "account_type": "Tax", + "tax_rate": 19.0 }, "Abziehbare Vorsteuer nach \u00a7 13b UStG 19 %": { "account_number": "1407" @@ -1197,15 +1203,15 @@ "is_group": 1, "Bewertungskorrektur zu Verb. aus Lieferungen und Leistungen": { "account_number": "9964" - }, - "Kreditoren": { - "account_number": "70000", - "is_group": 1, - "Wareneingangs-­Verrechnungskonto" : { - "account_number": "70001", - "account_type": "Stock Received But Not Billed" - } - }, + }, + "Kreditoren": { + "account_number": "70000", + "is_group": 1, + "Wareneingangs-­Verrechnungskonto" : { + "account_number": "70001", + "account_type": "Stock Received But Not Billed" + } + }, "Verb. aus Lieferungen und Leistungen": { "account_number": "3300", "account_type": "Payable" @@ -1488,17 +1494,21 @@ }, "Umsatzsteuer 7 %": { "account_number": "3801", - "account_type": "Tax" + "account_type": "Tax", + "tax_rate": 7.0 }, "Umsatzsteuer aus innergem. Erwerb": { "account_number": "3802" }, "Umsatzsteuer aus innergem. Erwerb 19 %": { - "account_number": "3804" + "account_number": "3804", + "account_type": "Tax", + "tax_rate": 19.0 }, "Umsatzsteuer 19 %": { "account_number": "3806", - "account_type": "Tax" + "account_type": "Tax", + "tax_rate": 19.0 }, "Umsatzsteuer aus im Inland steuerpfl. EU-Lieferungen": { "account_number": "3807" @@ -2295,49 +2305,49 @@ }, "6 - sonstige betriebliche Ertr\u00e4ge": { "root_type": "Income", - "is_group": 1, - "Erhaltene Boni (Gruppe)": { - "is_group": 1, - "Erhaltene Boni 7 % Vorsteuer": { - "account_number": "5750" - }, - "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe": { - "account_number": "5753" - }, - "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": { - "account_number": "5754" - }, - "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": { - "account_number": "5755" - }, - "Erhaltene Boni 19 % Vorsteuer": { - "account_number": "5760" - }, - "Erhaltene Boni": { - "account_number": "5769" - } - }, - "Erhaltene Rabatte (Gruppe)": { - "is_group": 1, - "Erhaltene Rabatte": { - "account_number": "5770" - }, - "Erhaltene Rabatte 7 % Vorsteuer": { - "account_number": "5780" - }, - "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe": { - "account_number": "5783" - }, - "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": { - "account_number": "5784" - }, - "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": { - "account_number": "5785" - }, - "Erhaltene Rabatte 19 % Vorsteuer": { - "account_number": "5790" - } - }, + "is_group": 1, + "Erhaltene Boni (Gruppe)": { + "is_group": 1, + "Erhaltene Boni 7 % Vorsteuer": { + "account_number": "5750" + }, + "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe": { + "account_number": "5753" + }, + "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": { + "account_number": "5754" + }, + "Erhaltene Boni aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": { + "account_number": "5755" + }, + "Erhaltene Boni 19 % Vorsteuer": { + "account_number": "5760" + }, + "Erhaltene Boni": { + "account_number": "5769" + } + }, + "Erhaltene Rabatte (Gruppe)": { + "is_group": 1, + "Erhaltene Rabatte": { + "account_number": "5770" + }, + "Erhaltene Rabatte 7 % Vorsteuer": { + "account_number": "5780" + }, + "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe": { + "account_number": "5783" + }, + "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 7% Vorsteuer": { + "account_number": "5784" + }, + "Erhaltene Rabatte aus Einkauf Roh-, Hilfs- und Betriebsstoffe 19% Vorsteuer": { + "account_number": "5785" + }, + "Erhaltene Rabatte 19 % Vorsteuer": { + "account_number": "5790" + } + }, "Andere aktivierte Eigenleistungen": { "account_number": "4820" }, @@ -2660,8 +2670,8 @@ }, "7 - sonstige betriebliche Aufwendungen": { "root_type": "Expense", - "is_group": 1, - "Erl\u00f6sschm\u00e4lerungen (Gruppe)": { + "is_group": 1, + "Erl\u00f6sschm\u00e4lerungen (Gruppe)": { "is_group": 1, "Erl\u00f6sschm\u00e4lerungen": { "account_number": "4700" @@ -2744,7 +2754,7 @@ "Gew\u00e4hrte Rabatte 19 % USt": { "account_number": "4790" } - }, + }, "Sonstige betriebliche Aufwendungen": { "account_number": "6300" }, From 6f3941c9cc67e7d445aa6a82a52d383d56745fe3 Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Mon, 16 Mar 2020 15:49:50 +0530 Subject: [PATCH 074/137] fix: remove make_purchase_invoice from demo script (#20906) currently demo fails with the following error: frappe@bf54a9834cfe:/workspace/development/frappe-bench$ bench --site test1.localhost execute erpnext.demo.demo.make Traceback (most recent call last): File "/usr/lib/python3.7/runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "/usr/lib/python3.7/runpy.py", line 85, in _run_code exec(code, run_globals) File "/workspace/development/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 97, in main() File "/workspace/development/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 18, in main click.Group(commands=commands)(prog_name='bench') File "/workspace/development/frappe-bench/env/lib/python3.7/site-packages/click/core.py", line 764, in __call__ return self.main(*args, **kwargs) File "/workspace/development/frappe-bench/env/lib/python3.7/site-packages/click/core.py", line 717, in main rv = self.invoke(ctx) File "/workspace/development/frappe-bench/env/lib/python3.7/site-packages/click/core.py", line 1137, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "/workspace/development/frappe-bench/env/lib/python3.7/site-packages/click/core.py", line 1137, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "/workspace/development/frappe-bench/env/lib/python3.7/site-packages/click/core.py", line 956, in invoke return ctx.invoke(self.callback, **ctx.params) File "/workspace/development/frappe-bench/env/lib/python3.7/site-packages/click/core.py", line 555, in invoke return callback(*args, **kwargs) File "/workspace/development/frappe-bench/env/lib/python3.7/site-packages/click/decorators.py", line 17, in new_func return f(get_current_context(), *args, **kwargs) File "/workspace/development/frappe-bench/apps/frappe/frappe/commands/__init__.py", line 25, in _func ret = f(frappe._dict(ctx.obj), *args, **kwargs) File "/workspace/development/frappe-bench/apps/frappe/frappe/commands/utils.py", line 145, in execute ret = frappe.get_attr(method)(*args, **kwargs) File "/workspace/development/frappe-bench/apps/frappe/frappe/__init__.py", line 1042, in get_attr return getattr(get_module(modulename), methodname) File "/workspace/development/frappe-bench/apps/frappe/frappe/__init__.py", line 823, in get_module return importlib.import_module(modulename) File "/workspace/development/frappe-bench/env/lib/python3.7/importlib/__init__.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "", line 1006, in _gcd_import File "", line 983, in _find_and_load File "", line 967, in _find_and_load_unlocked File "", line 677, in _load_unlocked File "", line 728, in exec_module File "", line 219, in _call_with_frames_removed File "/workspace/development/frappe-bench/apps/erpnext/erpnext/demo/demo.py", line 6, in from erpnext.demo.user import hr, sales, purchase, manufacturing, stock, accounts, projects, fixed_asset File "/workspace/development/frappe-bench/apps/erpnext/erpnext/demo/user/fixed_asset.py", line 9, in from erpnext.assets.doctype.asset.asset import make_purchase_invoice, make_sales_invoice ImportError: cannot import name 'make_purchase_invoice' from 'erpnext.assets.doctype.asset.asset' (/workspace/development/frappe-bench/apps/erpnext/erpnext/assets/doctype/asset/asset.py) Signed-off-by: Chinmay D. Pai --- erpnext/demo/user/fixed_asset.py | 39 +++++++++----------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/erpnext/demo/user/fixed_asset.py b/erpnext/demo/user/fixed_asset.py index e6d16872024..dc094e1c918 100644 --- a/erpnext/demo/user/fixed_asset.py +++ b/erpnext/demo/user/fixed_asset.py @@ -6,46 +6,28 @@ from __future__ import unicode_literals import frappe from frappe.utils.make_random import get_random -from erpnext.assets.doctype.asset.asset import make_purchase_invoice, make_sales_invoice +from erpnext.assets.doctype.asset.asset import make_sales_invoice from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset + def work(): frappe.set_user(frappe.db.get_global('demo_accounts_user')) - asset_list = make_asset_purchase_entry() - - if not asset_list: - # fixed_asset.work() already run - return - # Enable booking asset depreciation entry automatically frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1) - + # post depreciation entries as on today post_depreciation_entries() - + # scrap a random asset frappe.db.set_value("Company", "Wind Power LLC", "disposal_account", "Gain/Loss on Asset Disposal - WPL") - + asset = get_random_asset() scrap_asset(asset.name) - - # Sell a random asset - sell_an_asset() -def make_asset_purchase_entry(): - asset_list = frappe.get_all("Asset", filters={"purchase_invoice": ["in", ("", None)]}, - fields=["name", "item_code", "gross_purchase_amount", "company", "purchase_date"]) - - # make purchase invoice - for asset in asset_list: - pi = make_purchase_invoice(asset.name, asset.item_code, asset.gross_purchase_amount, - asset.company, asset.purchase_date) - pi.supplier = get_random("Supplier") - pi.save() - pi.submit() - - return asset_list + # Sell a random asset + sell_an_asset() + def sell_an_asset(): asset = get_random_asset() @@ -55,8 +37,9 @@ def sell_an_asset(): if asset.value_after_depreciation else asset.gross_purchase_amount * 0.9 si.save() si.submit() - + + def get_random_asset(): return frappe.db.sql(""" select name, item_code, value_after_depreciation, gross_purchase_amount - from `tabAsset` + from `tabAsset` where docstatus=1 and status not in ("Scrapped", "Sold") order by rand() limit 1""", as_dict=1)[0] From 46053f6c8f572195bf665adf346d10e5c9139d69 Mon Sep 17 00:00:00 2001 From: Prssanna Desai Date: Mon, 16 Mar 2020 15:52:00 +0530 Subject: [PATCH 075/137] fix: fix options of currency fieldtype in Expense Taxes and Charges (#20910) --- .../expense_taxes_and_charges/expense_taxes_and_charges.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json index 9bf69daf65a..1b1889b205f 100644 --- a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json +++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json @@ -70,7 +70,7 @@ "label": "Amount", "oldfieldname": "tax_amount", "oldfieldtype": "Currency", - "options": "currency" + "options": "Company:company:default_currency" }, { "columns": 2, @@ -80,7 +80,7 @@ "label": "Total", "oldfieldname": "total", "oldfieldtype": "Currency", - "options": "currency", + "options": "Company:company:default_currency", "read_only": 1 }, { From 37886a72efc4f9f9a2ffccd9fa1e396508230abd Mon Sep 17 00:00:00 2001 From: Vishal Dhayagude Date: Mon, 16 Mar 2020 15:57:42 +0530 Subject: [PATCH 076/137] fix(HR): Leave application company field made read-only and filter in Monthly attendance sheet (#20911) * fix(HR): Leave application company field made Readonly * fix: in monthly report attandance employee filter based on company * fix: minor typo --- .../leave_application/leave_application.json | 666 +++++++++--------- .../monthly_attendance_sheet.py | 6 +- 2 files changed, 338 insertions(+), 334 deletions(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.json b/erpnext/hr/doctype/leave_application/leave_application.json index cdb1add3918..460be514b59 100644 --- a/erpnext/hr/doctype/leave_application/leave_application.json +++ b/erpnext/hr/doctype/leave_application/leave_application.json @@ -1,332 +1,336 @@ { - "allow_import": 1, - "autoname": "naming_series:", - "creation": "2013-02-20 11:18:11", - "description": "Apply / Approve Leaves", - "doctype": "DocType", - "document_type": "Document", - "engine": "InnoDB", - "field_order": [ - "naming_series", - "employee", - "employee_name", - "column_break_4", - "leave_type", - "department", - "leave_balance", - "section_break_5", - "from_date", - "to_date", - "half_day", - "half_day_date", - "total_leave_days", - "column_break1", - "description", - "section_break_7", - "leave_approver", - "leave_approver_name", - "column_break_18", - "status", - "salary_slip", - "sb10", - "posting_date", - "follow_via_email", - "color", - "column_break_17", - "company", - "letter_head", - "amended_from" - ], - "fields": [ - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "no_copy": 1, - "options": "HR-LAP-.YYYY.-", - "print_hide": 1, - "reqd": 1, - "set_only_once": 1 - }, - { - "fieldname": "employee", - "fieldtype": "Link", - "in_global_search": 1, - "in_standard_filter": 1, - "label": "Employee", - "options": "Employee", - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "employee_name", - "fieldtype": "Data", - "in_global_search": 1, - "label": "Employee Name", - "read_only": 1 - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "leave_type", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Leave Type", - "options": "Leave Type", - "reqd": 1, - "search_index": 1 - }, - { - "fetch_from": "employee.department", - "fieldname": "department", - "fieldtype": "Link", - "label": "Department", - "options": "Department", - "read_only": 1 - }, - { - "fieldname": "leave_balance", - "fieldtype": "Float", - "label": "Leave Balance Before Application", - "no_copy": 1, - "read_only": 1 - }, - { - "fieldname": "section_break_5", - "fieldtype": "Section Break" - }, - { - "fieldname": "from_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "From Date", - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "to_date", - "fieldtype": "Date", - "label": "To Date", - "reqd": 1, - "search_index": 1 - }, - { - "default": "0", - "fieldname": "half_day", - "fieldtype": "Check", - "label": "Half Day" - }, - { - "depends_on": "eval:doc.half_day && (doc.from_date != doc.to_date)", - "fieldname": "half_day_date", - "fieldtype": "Date", - "label": "Half Day Date" - }, - { - "fieldname": "total_leave_days", - "fieldtype": "Float", - "in_list_view": 1, - "label": "Total Leave Days", - "no_copy": 1, - "precision": "1", - "read_only": 1 - }, - { - "fieldname": "column_break1", - "fieldtype": "Column Break", - "print_width": "50%", - "width": "50%" - }, - { - "fieldname": "description", - "fieldtype": "Small Text", - "label": "Reason" - }, - { - "fieldname": "section_break_7", - "fieldtype": "Section Break" - }, - { - "fieldname": "leave_approver", - "fieldtype": "Link", - "label": "Leave Approver", - "options": "User" - }, - { - "fieldname": "leave_approver_name", - "fieldtype": "Data", - "label": "Leave Approver Name", - "read_only": 1 - }, - { - "fieldname": "column_break_18", - "fieldtype": "Column Break" - }, - { - "default": "Open", - "fieldname": "status", - "fieldtype": "Select", - "in_standard_filter": 1, - "label": "Status", - "no_copy": 1, - "options": "Open\nApproved\nRejected\nCancelled" - }, - { - "fieldname": "sb10", - "fieldtype": "Section Break" - }, - { - "default": "Today", - "fieldname": "posting_date", - "fieldtype": "Date", - "label": "Posting Date", - "no_copy": 1, - "reqd": 1 - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company", - "remember_last_selected_value": 1, - "reqd": 1 - }, - { - "allow_on_submit": 1, - "default": "1", - "fieldname": "follow_via_email", - "fieldtype": "Check", - "label": "Follow via Email", - "print_hide": 1 - }, - { - "fieldname": "column_break_17", - "fieldtype": "Column Break" - }, - { - "fieldname": "salary_slip", - "fieldtype": "Link", - "label": "Salary Slip", - "options": "Salary Slip", - "print_hide": 1 - }, - { - "allow_on_submit": 1, - "fieldname": "letter_head", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Letter Head", - "options": "Letter Head", - "print_hide": 1 - }, - { - "allow_on_submit": 1, - "fieldname": "color", - "fieldtype": "Color", - "label": "Color", - "print_hide": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Amended From", - "no_copy": 1, - "options": "Leave Application", - "print_hide": 1, - "read_only": 1 - } - ], - "icon": "fa fa-calendar", - "idx": 1, - "is_submittable": 1, - "max_attachments": 3, - "modified": "2019-08-13 13:32:04.860848", - "modified_by": "Administrator", - "module": "HR", - "name": "Leave Application", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Employee", - "share": 1, - "write": 1 - }, - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "HR Manager", - "set_user_permissions": 1, - "share": 1, - "submit": 1, - "write": 1 - }, - { - "permlevel": 1, - "read": 1, - "role": "All" - }, - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "HR User", - "set_user_permissions": 1, - "share": 1, - "submit": 1, - "write": 1 - }, - { - "amend": 1, - "cancel": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Leave Approver", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "permlevel": 1, - "read": 1, - "report": 1, - "role": "HR User", - "write": 1 - }, - { - "permlevel": 1, - "read": 1, - "report": 1, - "role": "Leave Approver", - "write": 1 - } - ], - "search_fields": "employee,employee_name,leave_type,from_date,to_date,total_leave_days", - "sort_field": "modified", - "sort_order": "DESC", - "timeline_field": "employee", - "title_field": "employee_name" - } \ No newline at end of file + "actions": [], + "allow_import": 1, + "autoname": "naming_series:", + "creation": "2013-02-20 11:18:11", + "description": "Apply / Approve Leaves", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "naming_series", + "employee", + "employee_name", + "column_break_4", + "leave_type", + "department", + "leave_balance", + "section_break_5", + "from_date", + "to_date", + "half_day", + "half_day_date", + "total_leave_days", + "column_break1", + "description", + "section_break_7", + "leave_approver", + "leave_approver_name", + "column_break_18", + "status", + "salary_slip", + "sb10", + "posting_date", + "follow_via_email", + "color", + "column_break_17", + "company", + "letter_head", + "amended_from" + ], + "fields": [ + { + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "options": "HR-LAP-.YYYY.-", + "print_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, + { + "fieldname": "employee", + "fieldtype": "Link", + "in_global_search": 1, + "in_standard_filter": 1, + "label": "Employee", + "options": "Employee", + "reqd": 1, + "search_index": 1 + }, + { + "fieldname": "employee_name", + "fieldtype": "Data", + "in_global_search": 1, + "label": "Employee Name", + "read_only": 1 + }, + { + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, + { + "fieldname": "leave_type", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_standard_filter": 1, + "label": "Leave Type", + "options": "Leave Type", + "reqd": 1, + "search_index": 1 + }, + { + "fetch_from": "employee.department", + "fieldname": "department", + "fieldtype": "Link", + "label": "Department", + "options": "Department", + "read_only": 1 + }, + { + "fieldname": "leave_balance", + "fieldtype": "Float", + "label": "Leave Balance Before Application", + "no_copy": 1, + "read_only": 1 + }, + { + "fieldname": "section_break_5", + "fieldtype": "Section Break" + }, + { + "fieldname": "from_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "From Date", + "reqd": 1, + "search_index": 1 + }, + { + "fieldname": "to_date", + "fieldtype": "Date", + "label": "To Date", + "reqd": 1, + "search_index": 1 + }, + { + "default": "0", + "fieldname": "half_day", + "fieldtype": "Check", + "label": "Half Day" + }, + { + "depends_on": "eval:doc.half_day && (doc.from_date != doc.to_date)", + "fieldname": "half_day_date", + "fieldtype": "Date", + "label": "Half Day Date" + }, + { + "fieldname": "total_leave_days", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Total Leave Days", + "no_copy": 1, + "precision": "1", + "read_only": 1 + }, + { + "fieldname": "column_break1", + "fieldtype": "Column Break", + "print_width": "50%", + "width": "50%" + }, + { + "fieldname": "description", + "fieldtype": "Small Text", + "label": "Reason" + }, + { + "fieldname": "section_break_7", + "fieldtype": "Section Break" + }, + { + "fieldname": "leave_approver", + "fieldtype": "Link", + "label": "Leave Approver", + "options": "User" + }, + { + "fieldname": "leave_approver_name", + "fieldtype": "Data", + "label": "Leave Approver Name", + "read_only": 1 + }, + { + "fieldname": "column_break_18", + "fieldtype": "Column Break" + }, + { + "default": "Open", + "fieldname": "status", + "fieldtype": "Select", + "in_standard_filter": 1, + "label": "Status", + "no_copy": 1, + "options": "Open\nApproved\nRejected\nCancelled", + "permlevel": 1 + }, + { + "fieldname": "sb10", + "fieldtype": "Section Break" + }, + { + "default": "Today", + "fieldname": "posting_date", + "fieldtype": "Date", + "label": "Posting Date", + "no_copy": 1, + "reqd": 1 + }, + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "read_only": 1, + "remember_last_selected_value": 1, + "reqd": 1 + }, + { + "allow_on_submit": 1, + "default": "1", + "fieldname": "follow_via_email", + "fieldtype": "Check", + "label": "Follow via Email", + "print_hide": 1 + }, + { + "fieldname": "column_break_17", + "fieldtype": "Column Break" + }, + { + "fieldname": "salary_slip", + "fieldtype": "Link", + "label": "Salary Slip", + "options": "Salary Slip", + "print_hide": 1 + }, + { + "allow_on_submit": 1, + "fieldname": "letter_head", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Letter Head", + "options": "Letter Head", + "print_hide": 1 + }, + { + "allow_on_submit": 1, + "fieldname": "color", + "fieldtype": "Color", + "label": "Color", + "print_hide": 1 + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Amended From", + "no_copy": 1, + "options": "Leave Application", + "print_hide": 1, + "read_only": 1 + } + ], + "icon": "fa fa-calendar", + "idx": 1, + "is_submittable": 1, + "links": [], + "max_attachments": 3, + "modified": "2020-03-10 22:40:43.487721", + "modified_by": "Administrator", + "module": "HR", + "name": "Leave Application", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Employee", + "share": 1, + "write": 1 + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR Manager", + "set_user_permissions": 1, + "share": 1, + "submit": 1, + "write": 1 + }, + { + "permlevel": 1, + "read": 1, + "role": "All" + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR User", + "set_user_permissions": 1, + "share": 1, + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "cancel": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Leave Approver", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "permlevel": 1, + "read": 1, + "report": 1, + "role": "HR User", + "write": 1 + }, + { + "permlevel": 1, + "read": 1, + "report": 1, + "role": "Leave Approver", + "write": 1 + } + ], + "search_fields": "employee,employee_name,leave_type,from_date,to_date,total_leave_days", + "sort_field": "modified", + "sort_order": "DESC", + "timeline_field": "employee", + "title_field": "employee_name" +} diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py index 1e9c83bf3e6..aca3a175057 100644 --- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py +++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py @@ -13,7 +13,7 @@ def execute(filters=None): conditions, filters = get_conditions(filters) columns = get_columns(filters) att_map = get_attendance_list(conditions, filters) - emp_map = get_employee_details() + emp_map = get_employee_details(filters) holiday_list = [emp_map[d]["holiday_list"] for d in emp_map if emp_map[d]["holiday_list"]] default_holiday_list = frappe.get_cached_value('Company', filters.get("company"), "default_holiday_list") @@ -131,10 +131,10 @@ def get_conditions(filters): return conditions, filters -def get_employee_details(): +def get_employee_details(filters): emp_map = frappe._dict() for d in frappe.db.sql("""select name, employee_name, designation, department, branch, company, - holiday_list from tabEmployee""", as_dict=1): + holiday_list from tabEmployee where company = "%s" """ % (filters.get("company")), as_dict=1): emp_map.setdefault(d.name, d) return emp_map From 43a0011987a0badcbc39c1c26f80192e7d200199 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 16 Mar 2020 16:28:54 +0530 Subject: [PATCH 077/137] fix: serial_no_selector showing for non serialized batched item (#20852) --- erpnext/stock/doctype/stock_entry/stock_entry.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index ea27c6f5d5b..92cc8f65047 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -886,10 +886,8 @@ erpnext.stock.select_batch_and_serial_no = (frm, item) => { } } - if(item && item.has_serial_no - && frm.doc.purpose === 'Material Receipt') { - return; - } + if(item && !item.has_serial_no && item.has_batch_no) return; + if (frm.doc.purpose === 'Material Receipt') return; frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() { new erpnext.SerialNoBatchSelector({ From 11fb93d022db092ea2e9ab4f6cb3f0d82f655d23 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 16 Mar 2020 16:54:34 +0530 Subject: [PATCH 078/137] fix: Add bank transaction in module view (#20823) --- erpnext/config/accounts.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py index ab75f211c04..3df5fcc3ebd 100644 --- a/erpnext/config/accounts.py +++ b/erpnext/config/accounts.py @@ -181,6 +181,11 @@ def get_data(): "name": "Payment Reconciliation", "description": _("Match non-linked Invoices and Payments.") }, + { + "type": "doctype", + "label": _("Invoice Discounting"), + "name": "Invoice Discounting", + }, { "type": "doctype", "label": _("Update Bank Transaction Dates"), @@ -189,8 +194,9 @@ def get_data(): }, { "type": "doctype", - "label": _("Invoice Discounting"), - "name": "Invoice Discounting", + "label": _("Bank Transaction"), + "name": "Bank Transaction", + "doctype": "Bank Transaction" }, { "type": "report", From 5c760175d199a0e579073440d316773c4f0f4377 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 16 Mar 2020 17:26:02 +0530 Subject: [PATCH 079/137] fix: deletion of auto-created batch (#20953) --- erpnext/controllers/stock_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index d13edc34573..c6d0c7c0a6e 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -239,7 +239,7 @@ class StockController(AccountsController): for d in self.items: if not d.batch_no: continue - serial_nos = [d.name for d in frappe.get_all("Serial No", {'batch_no': d.batch_no})] + serial_nos = [sr.name for sr in frappe.get_all("Serial No", {'batch_no': d.batch_no})] if serial_nos: frappe.db.set_value("Serial No", { 'name': ['in', serial_nos] }, "batch_no", None) From e7a6a4b009508216f9976655977abf9de1ef2ca4 Mon Sep 17 00:00:00 2001 From: Saqib Date: Mon, 16 Mar 2020 17:48:21 +0530 Subject: [PATCH 080/137] fix: is_pos gets reset on making s_inv from s_ord (#20887) * s_inv has is_pos default set as 1 --- erpnext/selling/doctype/sales_order/sales_order.py | 1 - erpnext/stock/doctype/delivery_note/delivery_note.py | 1 - 2 files changed, 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 4a365004da8..9e4a71d60e5 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -645,7 +645,6 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): target.set_advances() def set_missing_values(source, target): - target.is_pos = 0 target.ignore_pricing_rule = 1 target.flags.ignore_permissions = True target.run_method("set_missing_values") diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 39aad2e0071..3f74b54ce80 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -413,7 +413,6 @@ def make_sales_invoice(source_name, target_doc=None): invoiced_qty_map = get_invoiced_qty_map(source_name) def set_missing_values(source, target): - target.is_pos = 0 target.ignore_pricing_rule = 1 target.run_method("set_missing_values") target.run_method("set_po_nos") From 281a9fdf0735e9797014cfc18424d9044bc7d83e Mon Sep 17 00:00:00 2001 From: Rohan Date: Mon, 16 Mar 2020 17:57:15 +0530 Subject: [PATCH 081/137] fix: handle error handling (#20814) --- erpnext/stock/doctype/delivery_trip/delivery_trip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py index 77d322ed28d..209b1ef1468 100644 --- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py +++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py @@ -238,7 +238,7 @@ class DeliveryTrip(Document): try: directions = maps_client.directions(**directions_data) except Exception as e: - frappe.throw(_(e)) + frappe.throw(_(str(e))) return directions[0] if directions else False From d2a28370347a9473628ab236ce14e8e834ae9a22 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 16 Mar 2020 21:42:51 +0530 Subject: [PATCH 082/137] fix: bom replace tool issue (#20841) Co-authored-by: Nabin Hait --- erpnext/manufacturing/doctype/bom/bom.py | 8 ++++++ .../bom_update_tool/bom_update_tool.py | 27 ++++++++++++------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 7f7ffa14bfa..b2a0b18db5e 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -487,6 +487,14 @@ class BOM(WebsiteGenerator): self.scrap_material_cost = total_sm_cost self.base_scrap_material_cost = base_total_sm_cost + def update_new_bom(self, old_bom, new_bom, rate): + for d in self.get("items"): + if d.bom_no != old_bom: continue + + d.bom_no = new_bom + d.rate = rate + d.amount = (d.stock_qty or d.qty) * rate + def update_exploded_items(self): """ Update Flat BOM, following will be correct data""" self.get_exploded_items() diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py index 31a9fdb28ab..2758a423716 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py +++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py @@ -14,10 +14,13 @@ import click class BOMUpdateTool(Document): def replace_bom(self): self.validate_bom() - self.update_new_bom() + + unit_cost = get_new_bom_unit_cost(self.new_bom) + self.update_new_bom(unit_cost) + frappe.cache().delete_key('bom_children') bom_list = self.get_parent_boms(self.new_bom) - updated_bom = [] + with click.progressbar(bom_list) as bom_list: pass for bom in bom_list: @@ -26,7 +29,9 @@ class BOMUpdateTool(Document): # this is only used for versioning and we do not want # to make separate db calls by using load_doc_before_save # which proves to be expensive while doing bulk replace - bom_obj._doc_before_save = bom_obj.as_dict() + bom_obj._doc_before_save = bom_obj + bom_obj.update_new_bom(self.current_bom, self.new_bom, unit_cost) + bom_obj.update_exploded_items() bom_obj.calculate_cost() bom_obj.update_parent_cost() bom_obj.db_update() @@ -43,14 +48,10 @@ class BOMUpdateTool(Document): != frappe.db.get_value("BOM", self.new_bom, "item"): frappe.throw(_("The selected BOMs are not for the same item")) - def update_new_bom(self): - new_bom_unitcost = frappe.db.sql("""SELECT `total_cost`/`quantity` - FROM `tabBOM` WHERE name = %s""", self.new_bom) - new_bom_unitcost = flt(new_bom_unitcost[0][0]) if new_bom_unitcost else 0 - + def update_new_bom(self, unit_cost): frappe.db.sql("""update `tabBOM Item` set bom_no=%s, rate=%s, amount=stock_qty*%s where bom_no = %s and docstatus < 2 and parenttype='BOM'""", - (self.new_bom, new_bom_unitcost, new_bom_unitcost, self.current_bom)) + (self.new_bom, unit_cost, unit_cost, self.current_bom)) def get_parent_boms(self, bom, bom_list=[]): data = frappe.db.sql("""SELECT DISTINCT parent FROM `tabBOM Item` @@ -65,12 +66,18 @@ class BOMUpdateTool(Document): return list(set(bom_list)) +def get_new_bom_unit_cost(bom): + new_bom_unitcost = frappe.db.sql("""SELECT `total_cost`/`quantity` + FROM `tabBOM` WHERE name = %s""", bom) + + return flt(new_bom_unitcost[0][0]) if new_bom_unitcost else 0 + @frappe.whitelist() def enqueue_replace_bom(args): if isinstance(args, string_types): args = json.loads(args) - frappe.enqueue("erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.replace_bom", args=args, timeout=4000) + frappe.enqueue("erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.replace_bom", args=args, timeout=40000) frappe.msgprint(_("Queued for replacing the BOM. It may take a few minutes.")) @frappe.whitelist() From 0dcd5a0f341734b7a8975c5f63bbf5144396d3a5 Mon Sep 17 00:00:00 2001 From: Don-Leopardo <46027152+Don-Leopardo@users.noreply.github.com> Date: Mon, 16 Mar 2020 14:05:01 -0300 Subject: [PATCH 083/137] fix: sql injection (#20817) --- .../doctype/bank_guarantee/bank_guarantee.py | 4 ++++ .../patient_appointment/patient_appointment.py | 4 ++-- erpnext/hr/doctype/department/department.py | 13 +++++++++---- erpnext/regional/india/utils.py | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py index 9aa2ee271a4..f28a07431fe 100644 --- a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py +++ b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import frappe, json from frappe.model.document import Document from frappe import _ +from frappe.desk.search import sanitize_searchfield class BankGuarantee(Document): def validate(self): @@ -22,5 +23,8 @@ class BankGuarantee(Document): @frappe.whitelist() def get_vouchar_detials(column_list, doctype, docname): + column_list = json.loads(column_list) + for col in column_list: + sanitize_searchfield(col) return frappe.db.sql(''' select {columns} from `tab{doctype}` where name=%s''' .format(columns=", ".join(json.loads(column_list)), doctype=doctype), docname, as_dict=1)[0] diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py index 7aa41c546c0..12248fcdce3 100755 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py @@ -386,5 +386,5 @@ def get_procedure_prescribed(patient): return frappe.db.sql("""select pp.name, pp.procedure, pp.parent, ct.practitioner, ct.encounter_date, pp.practitioner, pp.date, pp.department from `tabPatient Encounter` ct, `tabProcedure Prescription` pp - where ct.patient='{0}' and pp.parent=ct.name and pp.appointment_booked=0 - order by ct.creation desc""".format(patient)) + where ct.patient=%(patient)s and pp.parent=ct.name and pp.appointment_booked=0 + order by ct.creation desc""", {"patient": patient}) diff --git a/erpnext/hr/doctype/department/department.py b/erpnext/hr/doctype/department/department.py index 9b2b5817660..2cef5092767 100644 --- a/erpnext/hr/doctype/department/department.py +++ b/erpnext/hr/doctype/department/department.py @@ -48,12 +48,17 @@ def get_abbreviated_name(name, company): @frappe.whitelist() def get_children(doctype, parent=None, company=None, is_root=False): condition = '' + var_dict = { + "name": get_root_of("Department"), + "parent": parent, + "company": company, + } if company == parent: - condition = "name='{0}'".format(get_root_of("Department")) + condition = "name=%(name)s" elif company: - condition = "parent_department='{0}' and company='{1}'".format(parent, company) + condition = "parent_department=%(parent)s and company=%(company)s" else: - condition = "parent_department = '{0}'".format(parent) + condition = "parent_department = %(parent)s" return frappe.db.sql(""" select @@ -62,7 +67,7 @@ def get_children(doctype, parent=None, company=None, is_root=False): from `tab{doctype}` where {condition} - order by name""".format(doctype=doctype, condition=condition), as_dict=1) + order by name""".format(doctype=doctype, condition=condition), var_dict, as_dict=1) @frappe.whitelist() def add_node(): diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index 0f9156a6b4c..831985fc7cc 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -464,7 +464,7 @@ def get_gstins_for_company(company): `tabDynamic Link`.parent = `tabAddress`.name and `tabDynamic Link`.parenttype = 'Address' and `tabDynamic Link`.link_doctype = 'Company' and - `tabDynamic Link`.link_name = '{0}'""".format(company)) + `tabDynamic Link`.link_name = %(company)s""", {"company": company}) return company_gstins def get_address_details(data, doc, company_address, billing_address): From dd8059a3aa5ff1c6f5d7daebf5826061848200b8 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 16 Mar 2020 22:36:32 +0530 Subject: [PATCH 084/137] fix: Mode of payment not fetcched in Item wise purchase register --- .../item_wise_purchase_register.py | 7 +++++-- .../item_wise_sales_register/item_wise_sales_register.py | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 4523f66deb4..d1547f8d2cb 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -201,7 +201,8 @@ def get_columns(additional_table_columns, filters): { 'label': _('Mode Of Payment'), 'fieldname': 'mode_of_payment', - 'fieldtype': 'Data', + 'fieldtype': 'Link', + 'options': 'Mode of Payment', 'width': 120 }, { @@ -309,6 +310,8 @@ def get_items(filters, additional_query_columns): if additional_query_columns: additional_query_columns = ', ' + ', '.join(additional_query_columns) + else: + additional_query_columns = '' return frappe.db.sql(""" select @@ -320,7 +323,7 @@ def get_items(filters, additional_query_columns): `tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`, `tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`, `tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_amount`, - `tabPurchase Invoice`.supplier_name, `tabPurchase Invoice`.mode_of_payment {0} + `tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment` {0} from `tabPurchase Invoice`, `tabPurchase Invoice Item` where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and `tabPurchase Invoice`.docstatus = 1 %s diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 786e04dd5aa..0c8957ae441 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -373,6 +373,8 @@ def get_items(filters, additional_query_columns): if additional_query_columns: additional_query_columns = ', ' + ', '.join(additional_query_columns) + else: + additional_query_columns = '' return frappe.db.sql(""" select From 7c0e89d7857baeb32ab331972101e7a5c9070bed Mon Sep 17 00:00:00 2001 From: nmimsnikhil <56826544+nmimsnikhil@users.noreply.github.com> Date: Mon, 16 Mar 2020 22:41:23 +0530 Subject: [PATCH 085/137] fix: added a Reason for Rejection field for each items (#20828) * fix: added a Reason for Rejection field for each items * Update delivery_note_item.json Co-authored-by: Nabin Hait --- .../delivery_note_item.json | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index 782ac84e57d..a3386fce193 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -81,6 +81,8 @@ "accounting_dimensions_section", "cost_center", "dimension_col_break", + "reason_for_return_section_break", + "reason_for_return", "section_break_72", "page_break" ], @@ -699,12 +701,26 @@ { "fieldname": "dimension_col_break", "fieldtype": "Column Break" + }, + { + "depends_on": "eval:parent.is_return==1", + "fieldname": "reason_for_return", + "fieldtype": "Small Text", + "label": "Reason for Return", + "no_copy": 1 + }, + { + "default": "0", + "depends_on": "eval:parent.is_return==1", + "fieldname": "reason_for_return_section_break", + "fieldtype": "Section Break", + "label": "Reason For Return" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2020-03-05 14:18:33.131672", + "modified": "2020-03-06 14:18:33.131672", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", @@ -712,4 +728,4 @@ "permissions": [], "sort_field": "modified", "sort_order": "DESC" -} \ No newline at end of file +} From b9e1d9ad7d1fec9a29f083cbc581727b44129301 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Mon, 16 Mar 2020 22:44:17 +0530 Subject: [PATCH 086/137] Deduction based on earnins/gross pay (#20935) * fix: deductions calculation based on gross pay * test: salary structure deduction based on gross pay Co-authored-by: Nabin Hait --- .../additional_salary/additional_salary.py | 6 ++- erpnext/hr/doctype/salary_slip/salary_slip.py | 48 ++++++++++--------- .../salary_structure/test_salary_structure.py | 24 +++++++++- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/erpnext/hr/doctype/additional_salary/additional_salary.py b/erpnext/hr/doctype/additional_salary/additional_salary.py index 8498b3d277d..bc7dcee55e4 100644 --- a/erpnext/hr/doctype/additional_salary/additional_salary.py +++ b/erpnext/hr/doctype/additional_salary/additional_salary.py @@ -39,19 +39,21 @@ class AdditionalSalary(Document): return amount_per_day * no_of_days @frappe.whitelist() -def get_additional_salary_component(employee, start_date, end_date): +def get_additional_salary_component(employee, start_date, end_date, component_type): additional_components = frappe.db.sql(""" select salary_component, sum(amount) as amount, overwrite_salary_structure_amount, deduct_full_tax_on_selected_payroll_date from `tabAdditional Salary` where employee=%(employee)s and docstatus = 1 and payroll_date between %(from_date)s and %(to_date)s + and type = %(component_type)s group by salary_component, overwrite_salary_structure_amount order by salary_component, overwrite_salary_structure_amount """, { 'employee': employee, 'from_date': start_date, - 'to_date': end_date + 'to_date': end_date, + 'component_type': "Earning" if component_type == "earnings" else "Deduction" }, as_dict=1) additional_components_list = [] diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 0171643b13c..e126db5f5b1 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -298,9 +298,11 @@ class SalarySlip(TransactionBase): def calculate_net_pay(self): if self.salary_structure: - self.calculate_component_amounts() - + self.calculate_component_amounts("earnings") self.gross_pay = self.get_component_totals("earnings") + + if self.salary_structure: + self.calculate_component_amounts("deductions") self.total_deduction = self.get_component_totals("deductions") self.set_loan_repayment() @@ -308,25 +310,27 @@ class SalarySlip(TransactionBase): self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment)) self.rounded_total = rounded(self.net_pay) - def calculate_component_amounts(self): + def calculate_component_amounts(self, component_type): if not getattr(self, '_salary_structure_doc', None): self._salary_structure_doc = frappe.get_doc('Salary Structure', self.salary_structure) payroll_period = get_payroll_period(self.start_date, self.end_date, self.company) - self.add_structure_components() - self.add_employee_benefits(payroll_period) - self.add_additional_salary_components() - self.add_tax_components(payroll_period) - self.set_component_amounts_based_on_payment_days() + self.add_structure_components(component_type) + self.add_additional_salary_components(component_type) + if component_type == "earnings": + self.add_employee_benefits(payroll_period) + else: + self.add_tax_components(payroll_period) - def add_structure_components(self): + self.set_component_amounts_based_on_payment_days(component_type) + + def add_structure_components(self, component_type): data = self.get_data_for_eval() - for key in ('earnings', 'deductions'): - for struct_row in self._salary_structure_doc.get(key): - amount = self.eval_condition_and_formula(struct_row, data) - if amount and struct_row.statistical_component == 0: - self.update_component_row(struct_row, amount, key) + for struct_row in self._salary_structure_doc.get(component_type): + amount = self.eval_condition_and_formula(struct_row, data) + if amount and struct_row.statistical_component == 0: + self.update_component_row(struct_row, amount, component_type) def get_data_for_eval(self): '''Returns data for evaluating formula''' @@ -399,14 +403,15 @@ class SalarySlip(TransactionBase): amount = last_benefit.amount self.update_component_row(frappe._dict(last_benefit.struct_row), amount, "earnings") - def add_additional_salary_components(self): - additional_components = get_additional_salary_component(self.employee, self.start_date, self.end_date) + def add_additional_salary_components(self, component_type): + additional_components = get_additional_salary_component(self.employee, + self.start_date, self.end_date, component_type) if additional_components: for additional_component in additional_components: amount = additional_component.amount overwrite = additional_component.overwrite - key = "earnings" if additional_component.type == "Earning" else "deductions" - self.update_component_row(frappe._dict(additional_component.struct_row), amount, key, overwrite=overwrite) + self.update_component_row(frappe._dict(additional_component.struct_row), amount, + component_type, overwrite=overwrite) def add_tax_components(self, payroll_period): # Calculate variable_based_on_taxable_salary after all components updated in salary slip @@ -735,7 +740,7 @@ class SalarySlip(TransactionBase): total += d.amount return total - def set_component_amounts_based_on_payment_days(self): + def set_component_amounts_based_on_payment_days(self, component_type): joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee, ["date_of_joining", "relieving_date"]) @@ -745,9 +750,8 @@ class SalarySlip(TransactionBase): if not joining_date: frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name))) - for component_type in ("earnings", "deductions"): - for d in self.get(component_type): - d.amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0] + for d in self.get(component_type): + d.amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0] def set_loan_repayment(self): self.set('loans', []) diff --git a/erpnext/hr/doctype/salary_structure/test_salary_structure.py b/erpnext/hr/doctype/salary_structure/test_salary_structure.py index 848c3df57ab..f67a189ee71 100644 --- a/erpnext/hr/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/hr/doctype/salary_structure/test_salary_structure.py @@ -25,7 +25,6 @@ class TestSalaryStructure(unittest.TestCase): make_employee("test_employee@salary.com") make_employee("test_employee_2@salary.com") - def make_holiday_list(self): if not frappe.db.get_value("Holiday List", "Salary Structure Test Holiday List"): holiday_list = frappe.get_doc({ @@ -38,6 +37,29 @@ class TestSalaryStructure(unittest.TestCase): holiday_list.get_weekly_off_dates() holiday_list.save() + def test_salary_structure_deduction_based_on_gross_pay(self): + + emp = make_employee("test_employee_3@salary.com") + + sal_struct = make_salary_structure("Salary Structure 2", "Monthly", dont_submit = True) + + sal_struct.earnings = [sal_struct.earnings[0]] + sal_struct.earnings[0].amount_based_on_formula = 1 + sal_struct.earnings[0].formula = "base" + + sal_struct.deductions = [sal_struct.deductions[0]] + + sal_struct.deductions[0].amount_based_on_formula = 1 + sal_struct.deductions[0].condition = "gross_pay > 100" + sal_struct.deductions[0].formula = "gross_pay * 0.2" + + sal_struct.submit() + + assignment = create_salary_structure_assignment(emp, "Salary Structure 2") + ss = make_salary_slip(sal_struct.name, employee = emp) + + self.assertEqual(assignment.base * 0.2, ss.deductions[0].amount) + def test_amount_totals(self): frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0) sal_slip = frappe.get_value("Salary Slip", {"employee_name":"test_employee_2@salary.com"}) From 756f47af04d57fd402f5f0874e04a850f28c4850 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 17 Mar 2020 10:52:56 +0530 Subject: [PATCH 087/137] feat: Nested set filtering for accounting dimension (#20866) * feat: Nested set filtering for accounting dimension * fix: Remove print statement --- .../accounting_dimension/accounting_dimension.py | 14 +++++++++++++- .../accounts_receivable/accounts_receivable.py | 14 ++++++++------ erpnext/accounts/report/financial_statements.py | 13 ++++++++----- .../report/general_ledger/general_ledger.py | 11 +++++++---- .../report/sales_register/sales_register.py | 12 ++++++++---- .../accounts/report/trial_balance/trial_balance.py | 13 ++++++++----- 6 files changed, 52 insertions(+), 25 deletions(-) diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py index 522ed4ffa46..462d967d015 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py @@ -172,7 +172,7 @@ def get_doctypes_with_dimensions(): return doclist def get_accounting_dimensions(as_list=True): - accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled"]) + accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["label", "fieldname", "disabled", "document_type"]) if as_list: return [d.fieldname for d in accounting_dimensions] @@ -186,6 +186,18 @@ def get_checks_for_pl_and_bs_accounts(): return dimensions +def get_dimension_with_children(doctype, dimension): + + if isinstance(dimension, list): + dimension = dimension[0] + + all_dimensions = [] + lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"]) + children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}) + all_dimensions += [c.name for c in children] + + return all_dimensions + @frappe.whitelist() def get_dimension_filters(): dimension_filters = frappe.db.sql(""" diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 0438f6d09e1..240b0d83817 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -7,7 +7,7 @@ from frappe import _, scrub from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr, now, time_diff_in_seconds from collections import OrderedDict from erpnext.accounts.utils import get_currency_precision -from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children # This report gives a summary of all Outstanding Invoices considering the following @@ -603,7 +603,6 @@ class ReceivablePayableReport(object): self.add_supplier_filters(conditions, values) self.add_accounting_dimensions_filters(conditions, values) - return " and ".join(conditions), values def get_order_by_condition(self): @@ -666,13 +665,16 @@ class ReceivablePayableReport(object): doctype=doctype, lft=lft, rgt=rgt, key=key) def add_accounting_dimensions_filters(self, conditions, values): - accounting_dimensions = get_accounting_dimensions() + accounting_dimensions = get_accounting_dimensions(as_list=False) if accounting_dimensions: for dimension in accounting_dimensions: - if self.filters.get(dimension): - conditions.append("{0} = %s".format(dimension)) - values.append(self.filters.get(dimension)) + if self.filters.get(dimension.fieldname): + if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'): + self.filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, + self.filters.get(dimension.fieldname)) + conditions.append("{0} in %s".format(dimension.fieldname)) + values.append(tuple(self.filters.get(dimension.fieldname))) def get_gle_balance(self, gle): # get the balance of the GL (debit - credit) or reverse balance based on report type diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 75433a135f3..2636a1d2efc 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -16,7 +16,7 @@ from frappe import _ from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate, cstr) from six import itervalues -from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False, company=None, reset_period_on_fy_change=True): @@ -389,7 +389,7 @@ def set_gl_entries_by_account( def get_additional_conditions(from_date, ignore_closing_entries, filters): additional_conditions = [] - accounting_dimensions = get_accounting_dimensions() + accounting_dimensions = get_accounting_dimensions(as_list=False) if ignore_closing_entries: additional_conditions.append("ifnull(voucher_type, '')!='Period Closing Voucher'") @@ -412,11 +412,14 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters): additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)") else: additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)") - + if accounting_dimensions: for dimension in accounting_dimensions: - if filters.get(dimension): - additional_conditions.append("{0} in (%({0})s)".format(dimension)) + if filters.get(dimension.fieldname): + if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'): + filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, + filters.get(dimension.fieldname)) + additional_conditions.append("{0} in %({0})s".format(dimension.fieldname)) return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else "" diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 0939354efa7..f45911f90e5 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -10,7 +10,7 @@ from frappe import _, _dict from erpnext.accounts.utils import get_account_currency from erpnext.accounts.report.financial_statements import get_cost_centers_with_children from six import iteritems -from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children from collections import OrderedDict def execute(filters=None): @@ -194,12 +194,15 @@ def get_conditions(filters): if match_conditions: conditions.append(match_conditions) - accounting_dimensions = get_accounting_dimensions() + accounting_dimensions = get_accounting_dimensions(as_list=False) if accounting_dimensions: for dimension in accounting_dimensions: - if filters.get(dimension): - conditions.append("{0} in (%({0})s)".format(dimension)) + if filters.get(dimension.fieldname): + if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'): + filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, + filters.get(dimension.fieldname)) + conditions.append("{0} in %({0})s".format(dimension.fieldname)) return "and {}".format(" and ".join(conditions)) if conditions else "" diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 2be90bc5264..9864e40c1a9 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -6,7 +6,7 @@ import frappe from frappe.utils import flt from frappe import msgprint, _ from frappe.model.meta import get_field_precision -from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children def execute(filters=None): return _execute(filters) @@ -341,14 +341,18 @@ def get_conditions(filters): where parent=`tabSales Invoice`.name and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s)""" - accounting_dimensions = get_accounting_dimensions() + accounting_dimensions = get_accounting_dimensions(as_list=False) if accounting_dimensions: for dimension in accounting_dimensions: - if filters.get(dimension): + if filters.get(dimension.fieldname): + if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'): + filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, + filters.get(dimension.fieldname)) + conditions += """ and exists(select name from `tabSales Invoice Item` where parent=`tabSales Invoice`.name - and ifnull(`tabSales Invoice Item`.{0}, '') = %({0})s)""".format(dimension) + and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)""".format(dimension.fieldname) return conditions diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 69285cc9634..5fe6b416fda 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -7,7 +7,7 @@ from frappe import _ from frappe.utils import flt, getdate, formatdate, cstr from erpnext.accounts.report.financial_statements \ import filter_accounts, set_gl_entries_by_account, filter_out_zero_value_rows -from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions +from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit") @@ -109,7 +109,7 @@ def get_rootwise_opening_balances(filters, report_type): additional_conditions += fb_conditions - accounting_dimensions = get_accounting_dimensions() + accounting_dimensions = get_accounting_dimensions(as_list=False) query_filters = { "company": filters.company, @@ -122,11 +122,14 @@ def get_rootwise_opening_balances(filters, report_type): if accounting_dimensions: for dimension in accounting_dimensions: - if filters.get(dimension): - additional_conditions += """ and {0} in (%({0})s) """.format(dimension) + if filters.get(dimension.fieldname): + if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'): + filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type, + filters.get(dimension.fieldname)) + additional_conditions += "and {0} in %({0})s".format(dimension.fieldname) query_filters.update({ - dimension: filters.get(dimension) + dimension.fieldname: filters.get(dimension.fieldname) }) gle = frappe.db.sql(""" From 3ddcc2e5c77cda7cf82125e46d6fd0f54c58d26a Mon Sep 17 00:00:00 2001 From: Marica Date: Tue, 17 Mar 2020 10:56:13 +0530 Subject: [PATCH 088/137] fix: Item alternative must have similar fields as orignal item (#20799) * fix: Item alternative must have similar fields as orignal item * fix: Using db.get_values and meta instead of get_value and get_doc * fix: Made code more DRY Co-authored-by: Nabin Hait --- .../doctype/item_alternative/item_alternative.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/erpnext/stock/doctype/item_alternative/item_alternative.py b/erpnext/stock/doctype/item_alternative/item_alternative.py index 8e54539b18b..0c0d5b3271f 100644 --- a/erpnext/stock/doctype/item_alternative/item_alternative.py +++ b/erpnext/stock/doctype/item_alternative/item_alternative.py @@ -22,6 +22,21 @@ class ItemAlternative(Document): if self.item_code == self.alternative_item_code: frappe.throw(_("Alternative item must not be same as item code")) + item_meta = frappe.get_meta("Item") + fields = ["is_stock_item", "include_item_in_manufacturing","has_serial_no","has_batch_no"] + item_data = frappe.db.get_values("Item", self.item_code, fields, as_dict=1) + alternative_item_data = frappe.db.get_values("Item", self.alternative_item_code, fields, as_dict=1) + + for field in fields: + if item_data[0].get(field) != alternative_item_data[0].get(field): + raise_exception, alert = [1, False] if field == "is_stock_item" else [0, True] + + frappe.msgprint(_("The value of {0} differs between Items {1} and {2}") \ + .format(frappe.bold(item_meta.get_label(field)), + frappe.bold(self.alternative_item_code), + frappe.bold(self.item_code)), + alert=alert, raise_exception=raise_exception) + def validate_duplicate(self): if frappe.db.get_value("Item Alternative", {'item_code': self.item_code, 'alternative_item_code': self.alternative_item_code, 'name': ('!=', self.name)}): From 7f58f6af3997fcd6d52460d107cb9082e70d3cba Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Tue, 17 Mar 2020 10:58:17 +0530 Subject: [PATCH 089/137] fix: leave based on multiple holiday list (#20849) Co-authored-by: Nabin Hait --- .../leave_application/leave_application.py | 20 +++++++++++-------- .../leave_ledger_entry.json | 11 +++++++++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 8c109464fdf..39e5e1132ca 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -366,7 +366,8 @@ class LeaveApplication(Document): leaves=self.total_leave_days * -1, from_date=self.from_date, to_date=self.to_date, - is_lwp=lwp + is_lwp=lwp, + holiday_list=get_holiday_list_for_employee(self.employee) ) create_leave_ledger_entry(self, args, submit) @@ -376,7 +377,9 @@ class LeaveApplication(Document): from_date=self.from_date, to_date=expiry_date, leaves=(date_diff(expiry_date, self.from_date) + 1) * -1, - is_lwp=lwp + is_lwp=lwp, + holiday_list=get_holiday_list_for_employee(self.employee), + ) create_leave_ledger_entry(self, args, submit) @@ -402,7 +405,7 @@ def get_allocation_expiry(employee, leave_type, to_date, from_date): return expiry[0]['to_date'] if expiry else None @frappe.whitelist() -def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None): +def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None, holiday_list = None): number_of_days = 0 if cint(half_day) == 1: if from_date == to_date: @@ -416,7 +419,7 @@ def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day number_of_days = date_diff(to_date, from_date) + 1 if not frappe.db.get_value("Leave Type", leave_type, "include_holiday"): - number_of_days = flt(number_of_days) - flt(get_holidays(employee, from_date, to_date)) + number_of_days = flt(number_of_days) - flt(get_holidays(employee, from_date, to_date, holiday_list=holiday_list)) return number_of_days @frappe.whitelist() @@ -567,7 +570,7 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date): {'name': leave_entry.transaction_name}, ['half_day_date']) leave_days += get_number_of_leave_days(employee, leave_type, - leave_entry.from_date, leave_entry.to_date, half_day, half_day_date) * -1 + leave_entry.from_date, leave_entry.to_date, half_day, half_day_date, holiday_list=leave_entry.holiday_list) * -1 return leave_days @@ -580,7 +583,7 @@ def get_leave_entries(employee, leave_type, from_date, to_date): ''' Returns leave entries between from_date and to_date ''' return frappe.db.sql(""" SELECT - employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type, + employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type, holiday_list, is_carry_forward, is_expired FROM `tabLeave Ledger Entry` WHERE employee=%(employee)s AND leave_type=%(leave_type)s @@ -596,9 +599,10 @@ def get_leave_entries(employee, leave_type, from_date, to_date): }, as_dict=1) @frappe.whitelist() -def get_holidays(employee, from_date, to_date): +def get_holidays(employee, from_date, to_date, holiday_list = None): '''get holidays between two dates for the given employee''' - holiday_list = get_holiday_list_for_employee(employee) + if not holiday_list: + holiday_list = get_holiday_list_for_employee(employee) holidays = frappe.db.sql("""select count(distinct holiday_date) from `tabHoliday` h1, `tabHoliday List` h2 where h1.parent = h2.name and h1.holiday_date between %s and %s diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json index 771e706bbb3..a5ac3f3d471 100644 --- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json +++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2019-05-09 15:47:39.760406", "doctype": "DocType", "engine": "InnoDB", @@ -12,6 +13,7 @@ "column_break_7", "from_date", "to_date", + "holiday_list", "is_carry_forward", "is_expired", "is_lwp", @@ -98,11 +100,18 @@ "fieldname": "is_lwp", "fieldtype": "Check", "label": "Is Leave Without Pay" + }, + { + "fieldname": "holiday_list", + "fieldtype": "Link", + "label": "Holiday List", + "options": "Holiday List" } ], "in_create": 1, "is_submittable": 1, - "modified": "2019-08-20 14:40:04.130799", + "links": [], + "modified": "2020-02-27 14:40:10.502605", "modified_by": "Administrator", "module": "HR", "name": "Leave Ledger Entry", From 6f454dce20fe1b78e106e6cdc8680dba732afbc7 Mon Sep 17 00:00:00 2001 From: Sun Howwrongbum Date: Tue, 17 Mar 2020 12:13:01 +0530 Subject: [PATCH 090/137] fix: null fields being set in Integration Request (#20894) Co-authored-by: Nabin Hait --- .../accounts/doctype/payment_request/payment_request.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 1aff43c7177..6b74f477f2b 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -126,12 +126,12 @@ class PaymentRequest(Document): return controller.get_payment_url(**{ "amount": flt(self.grand_total, self.precision("grand_total")), - "title": data.company.encode("utf-8"), - "description": self.subject.encode("utf-8"), + "title": frappe.as_unicode(data.company), + "description": frappe.as_unicode(self.subject), "reference_doctype": "Payment Request", "reference_docname": self.name, "payer_email": self.email_to or frappe.session.user, - "payer_name": frappe.safe_encode(data.customer_name), + "payer_name": frappe.as_unicode(data.customer_name), "order_id": self.name, "currency": self.currency }) @@ -475,4 +475,4 @@ def make_payment_order(source_name, target_doc=None): } }, target_doc, set_missing_values) - return doclist \ No newline at end of file + return doclist From 224059e7bac7479f41432e1b30a5326687c42360 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 17 Mar 2020 16:59:09 +0530 Subject: [PATCH 091/137] fix: Party Name not visible in statement of accounts (#20914) * fix: Party name in Statement Of Accounts * Update general_ledger.html Co-authored-by: Nabin Hait --- erpnext/accounts/report/general_ledger/general_ledger.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html index 40469aecc1d..9a2205a5791 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.html +++ b/erpnext/accounts/report/general_ledger/general_ledger.html @@ -2,7 +2,7 @@

{% if (filters.party_name) { %} {%= filters.party_name %} - {% } else if (filters.party && filters.show_name) { %} + {% } else if (filters.party) { %} {%= filters.party %} {% } else if (filters.account) { %} {%= filters.account %} From bc8a881e649e9ee7d0001e061e04ea59e86e6507 Mon Sep 17 00:00:00 2001 From: Saqib Date: Tue, 17 Mar 2020 17:00:24 +0530 Subject: [PATCH 092/137] fix: purchase return are allowed even when assets are not cancelled (#20798) * fix: purchase return are allowed even when assets are not cancelled * chore: test case * fix: error message Co-authored-by: Nabin Hait --- erpnext/controllers/buying_controller.py | 14 ++++++++++ .../purchase_receipt/test_purchase_receipt.py | 27 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 75b896bb134..a47507eaf7b 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -44,6 +44,7 @@ class BuyingController(StockController): self.validate_stock_or_nonstock_items() self.validate_warehouse() self.set_supplier_address() + self.validate_asset_return() if self.doctype=="Purchase Invoice": self.validate_purchase_receipt_if_update_stock() @@ -99,6 +100,19 @@ class BuyingController(StockController): for d in tax_for_valuation: d.category = 'Total' msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items')) + + def validate_asset_return(self): + if self.doctype not in ['Purchase Receipt', 'Purchase Invoice'] or not self.is_return: + return + + purchase_doc_field = 'purchase_receipt' if self.doctype == 'Purchase Receipt' else 'purchase_invoice' + not_cancelled_asset = [d.name for d in frappe.db.get_all("Asset", { + purchase_doc_field: self.return_against, + "docstatus": 1 + })] + if self.is_return and len(not_cancelled_asset): + frappe.throw(_("{} has submitted assets linked to it. You need to cancel the assets to create purchase return.".format(self.return_against)), + title=_("Not Allowed")) def get_asset_items(self): if self.doctype not in ['Purchase Order', 'Purchase Invoice', 'Purchase Receipt']: diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 6e19b71cac8..a51b25bf36d 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -374,6 +374,33 @@ class TestPurchaseReceipt(unittest.TestCase): location = frappe.db.get_value('Asset', assets[0].name, 'location') self.assertEquals(location, "Test Location") + + def test_purchase_return_with_submitted_asset(self): + from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_return + + pr = make_purchase_receipt(item_code="Test Asset Item", qty=1) + + asset = frappe.get_doc("Asset", { + 'purchase_receipt': pr.name + }) + asset.available_for_use_date = frappe.utils.nowdate() + asset.gross_purchase_amount = 50.0 + asset.append("finance_books", { + "expected_value_after_useful_life": 10, + "depreciation_method": "Straight Line", + "total_number_of_depreciations": 3, + "frequency_of_depreciation": 1, + "depreciation_start_date": frappe.utils.nowdate() + }) + asset.submit() + + pr_return = make_purchase_return(pr.name) + self.assertRaises(frappe.exceptions.ValidationError, pr_return.submit) + + asset.load_from_db() + asset.cancel() + + pr_return.submit() def test_purchase_receipt_for_enable_allow_cost_center_in_entry_of_bs_account(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center From a6cd666b10a41566e450433be3ffac9abd0643b9 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 17 Mar 2020 17:00:41 +0530 Subject: [PATCH 093/137] fix: reserved qty for production issue for partial completion of work order (#20900) --- .../doctype/work_order/test_work_order.py | 34 ++++++++++++++++++- .../doctype/work_order/work_order.py | 6 ++-- erpnext/stock/doctype/bin/bin.py | 14 +++++--- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index ea2e7a96e1d..f917b098688 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -14,6 +14,7 @@ from erpnext.stock.utils import get_bin from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.stock.doctype.item.test_item import make_item from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom +from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse class TestWorkOrder(unittest.TestCase): def setUp(self): @@ -82,6 +83,37 @@ class TestWorkOrder(unittest.TestCase): wo_order.set_work_order_operations() self.assertEqual(wo_order.planned_operating_cost, cost*2) + def test_resered_qty_for_partial_completion(self): + item = "_Test Item" + warehouse = create_warehouse("Test Warehouse for reserved_qty - _TC") + + bin1_at_start = get_bin(item, warehouse) + + # reset to correct value + bin1_at_start.update_reserved_qty_for_production() + + wo_order = make_wo_order_test_record(item="_Test FG Item", qty=2, + source_warehouse=warehouse, skip_transfer=1) + + bin1_on_submit = get_bin(item, warehouse) + + # reserved qty for production is updated + self.assertEqual(cint(bin1_at_start.reserved_qty_for_production) + 2, + cint(bin1_on_submit.reserved_qty_for_production)) + + test_stock_entry.make_stock_entry(item_code="_Test Item", + target=warehouse, qty=100, basic_rate=100) + test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100", + target=warehouse, qty=100, basic_rate=100) + + s = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 1)) + s.submit() + + bin1_at_completion = get_bin(item, warehouse) + + self.assertEqual(cint(bin1_at_completion.reserved_qty_for_production), + cint(bin1_on_submit.reserved_qty_for_production) - 1) + def test_production_item(self): wo_order = make_wo_order_test_record(item="_Test FG Item", qty=1, do_not_save=True) frappe.db.set_value("Item", "_Test FG Item", "end_of_life", "2000-1-1") @@ -368,7 +400,7 @@ def make_wo_order_test_record(**args): wo_order.company = args.company or "_Test Company" wo_order.stock_uom = args.stock_uom or "_Test UOM" wo_order.use_multi_level_bom=0 - wo_order.skip_transfer=1 + wo_order.skip_transfer=args.skip_transfer or 0 wo_order.get_items_and_operations_from_bom() wo_order.sales_order = args.sales_order or None diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index b4dc3a55699..28bcc2e0f9c 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -429,6 +429,9 @@ class WorkOrder(Document): update bin reserved_qty_for_production called from Stock Entry for production, after submit, cancel ''' + # calculate consumed qty based on submitted stock entries + self.update_consumed_qty_for_required_items() + if self.docstatus==1: # calculate transferred qty based on submitted stock entries self.update_transaferred_qty_for_required_items() @@ -436,9 +439,6 @@ class WorkOrder(Document): # update in bin self.update_reserved_qty_for_production() - # calculate consumed qty based on submitted stock entries - self.update_consumed_qty_for_required_items() - def update_reserved_qty_for_production(self, items=None): '''update reserved_qty_for_production in bins''' for d in self.required_items: diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index 97a84726da8..73b36e3d852 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -69,15 +69,21 @@ class Bin(Document): '''Update qty reserved for production from Production Item tables in open work orders''' self.reserved_qty_for_production = frappe.db.sql(''' - select sum(item.required_qty - item.transferred_qty) - from `tabWork Order` pro, `tabWork Order Item` item - where + SELECT + CASE WHEN ifnull(skip_transfer, 0) = 0 THEN + SUM(item.required_qty - item.transferred_qty) + ELSE + SUM(item.required_qty - item.consumed_qty) + END + FROM `tabWork Order` pro, `tabWork Order Item` item + WHERE item.item_code = %s and item.parent = pro.name and pro.docstatus = 1 and item.source_warehouse = %s and pro.status not in ("Stopped", "Completed") - and item.required_qty > item.transferred_qty''', (self.item_code, self.warehouse))[0][0] + and (item.required_qty > item.transferred_qty or item.required_qty > item.consumed_qty) + ''', (self.item_code, self.warehouse))[0][0] self.set_projected_qty() From 738517c6e81218e89a4a00ade5cc0d6551d7658e Mon Sep 17 00:00:00 2001 From: Priyanka Gangar <59438065+0925-pinka@users.noreply.github.com> Date: Tue, 17 Mar 2020 19:39:06 +0530 Subject: [PATCH 094/137] Label changes in account settings hotfix (#20964) * fix: Account setting words switches to US Terminology * created united_states.js * Remove Unwanted Spaces * Remove all changes * Add spaces between arguments Co-authored-by: PriyankaGangar --- .../doctype/accounts_settings/regional/united_states.js | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 erpnext/accounts/doctype/accounts_settings/regional/united_states.js diff --git a/erpnext/accounts/doctype/accounts_settings/regional/united_states.js b/erpnext/accounts/doctype/accounts_settings/regional/united_states.js new file mode 100644 index 00000000000..d47d6e58039 --- /dev/null +++ b/erpnext/accounts/doctype/accounts_settings/regional/united_states.js @@ -0,0 +1,8 @@ + +frappe.ui.form.on('Accounts Settings', { + refresh: function(frm) { + frm.set_df_property("acc_frozen_upto", "label", "Books Closed Through"); + frm.set_df_property("frozen_accounts_modifier", "label", "Role Allowed to Close Books & Make Changes to Closed Periods"); + frm.set_df_property("credit_controller", "label", "Credit Manager"); + } +}); \ No newline at end of file From 7cf245895e84604ec141a3d5c88455c515c345b7 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Mon, 2 Dec 2019 17:08:12 +0530 Subject: [PATCH 095/137] refactor: Report BOM Sock Calculated (#19431) --- .../bom_stock_calculated.py | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py index be016ad9a47..f7b407b7922 100644 --- a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py +++ b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ +from frappe.utils.data import comma_and def execute(filters=None): # if not filters: filters = {} @@ -13,35 +14,36 @@ def execute(filters=None): data = get_bom_stock(filters) qty_to_make = filters.get("qty_to_make") + manufacture_details = get_manufacturer_records() for row in data: - item_map = get_item_details(row.item_code) reqd_qty = qty_to_make * row.actual_qty last_pur_price = frappe.db.get_value("Item", row.item_code, "last_purchase_rate") - if row.to_build > 0: - diff_qty = row.to_build - reqd_qty - summ_data.append([row.item_code, row.description, item_map[row.item_code]["manufacturer"], item_map[row.item_code]["manufacturer_part_no"], row.actual_qty, row.to_build, reqd_qty, diff_qty, last_pur_price]) - else: - diff_qty = 0 - reqd_qty - summ_data.append([row.item_code, row.description, item_map[row.item_code]["manufacturer"], item_map[row.item_code]["manufacturer_part_no"], row.actual_qty, "0.000", reqd_qty, diff_qty, last_pur_price]) + summ_data.append(get_report_data(last_pur_price, reqd_qty, row, manufacture_details)) return columns, summ_data +def get_report_data(last_pur_price, reqd_qty, row, manufacture_details): + to_build = row.to_build if row.to_build > 0 else 0 + diff_qty = to_build - reqd_qty + return [row.item_code, row.description, + comma_and(manufacture_details.get(row.item_code, {}).get('manufacturer', []), add_quotes=False), + comma_and(manufacture_details.get(row.item_code, {}).get('manufacturer_part', []), add_quotes=False), + row.actual_qty, str(to_build), + reqd_qty, diff_qty, last_pur_price] + def get_columns(): """return columns""" columns = [ _("Item") + ":Link/Item:100", _("Description") + "::150", - _("Manufacturer") + "::100", - _("Manufacturer Part Number") + "::100", + _("Manufacturer") + "::250", + _("Manufacturer Part Number") + "::250", _("Qty") + ":Float:50", _("Stock Qty") + ":Float:100", _("Reqd Qty")+ ":Float:100", _("Diff Qty")+ ":Float:100", _("Last Purchase Price")+ ":Float:100", - - ] - return columns def get_bom_stock(filters): @@ -85,7 +87,12 @@ def get_bom_stock(filters): GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom), as_dict=1) -def get_item_details(item_code): - items = frappe.db.sql("""select it.item_group, it.item_name, it.stock_uom, it.name, it.brand, it.description, it.manufacturer_part_no, it.manufacturer from tabItem it where it.item_code = %s""", item_code, as_dict=1) +def get_manufacturer_records(): + details = frappe.get_list('Item Manufacturer', fields = ["manufacturer", "manufacturer_part_no, parent"]) + manufacture_details = frappe._dict() + for detail in details: + dic = manufacture_details.setdefault(detail.get('parent'), {}) + dic.setdefault('manufacturer', []).append(detail.get('manufacturer')) + dic.setdefault('manufacturer_part', []).append(detail.get('manufacturer_part_no')) - return dict((d.name, d) for d in items) + return manufacture_details \ No newline at end of file From da7c6b0d99b6d8bf52cb14978e5bb8b862d631fa Mon Sep 17 00:00:00 2001 From: Marica Date: Wed, 18 Mar 2020 11:29:02 +0530 Subject: [PATCH 096/137] fix: Missing if condition in Customer Default Bank Account Validation. (#20970) --- erpnext/selling/doctype/customer/customer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 3248c998b60..791a3e1536a 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -76,7 +76,8 @@ class Customer(TransactionBase): def validate_default_bank_account(self): if self.default_bank_account: is_company_account = frappe.db.get_value('Bank Account', self.default_bank_account, 'is_company_account') - frappe.throw(_("{0} is not a company bank account").format(frappe.bold(self.default_bank_account))) + if not is_company_account: + frappe.throw(_("{0} is not a company bank account").format(frappe.bold(self.default_bank_account))) def on_update(self): self.validate_name_with_customer_group() From 1ed5993ff6f188201aa7c05440d56c479ad2e618 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 18 Mar 2020 13:33:55 +0530 Subject: [PATCH 097/137] fix: shortage qty in stock projected qty report --- .../stock/report/stock_projected_qty/stock_projected_qty.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py index 913d7d848ed..c8efb1637f9 100644 --- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py +++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py @@ -44,7 +44,9 @@ def execute(filters=None): re_order_level = d.warehouse_reorder_level re_order_qty = d.warehouse_reorder_qty - shortage_qty = re_order_level - flt(bin.projected_qty) if (re_order_level or re_order_qty) else 0 + shortage_qty = 0 + if (re_order_level or re_order_qty) and re_order_level > bin.projected_qty: + shortage_qty = re_order_level - flt(bin.projected_qty) data.append([item.name, item.item_name, item.description, item.item_group, item.brand, bin.warehouse, item.stock_uom, bin.actual_qty, bin.planned_qty, bin.indented_qty, bin.ordered_qty, From 210a718a0420ad88f28b2cc2679a8ce92ff2bd95 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 19 Mar 2020 10:03:06 +0530 Subject: [PATCH 098/137] fix: bom comparison issue --- erpnext/manufacturing/doctype/bom/bom.py | 4 ++++ .../bom_comparison_tool/bom_comparison_tool.js | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index b2a0b18db5e..19d36f6e8c4 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -823,6 +823,10 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None): def get_bom_diff(bom1, bom2): from frappe.model import table_fields + if bom1 == bom2: + frappe.throw(_("BOM 1 {0} and BOM 2 {1} should not be same") + .format(frappe.bold(bom1), frappe.bold(bom2))) + doc1 = frappe.get_doc('BOM', bom1) doc2 = frappe.get_doc('BOM', bom2) diff --git a/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js index 7152d3dff61..1bcb1efdaad 100644 --- a/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js +++ b/erpnext/manufacturing/page/bom_comparison_tool/bom_comparison_tool.js @@ -22,7 +22,14 @@ erpnext.BOMComparisonTool = class BOMComparisonTool { fieldname: 'name1', fieldtype: 'Link', options: 'BOM', - change: () => this.fetch_and_render() + change: () => this.fetch_and_render(), + get_query: () => { + return { + filters: { + "name": ["not in", [this.form.get_value("name2") || ""]] + } + } + } }, { fieldtype: 'Column Break' @@ -32,7 +39,14 @@ erpnext.BOMComparisonTool = class BOMComparisonTool { fieldname: 'name2', fieldtype: 'Link', options: 'BOM', - change: () => this.fetch_and_render() + change: () => this.fetch_and_render(), + get_query: () => { + return { + filters: { + "name": ["not in", [this.form.get_value("name1") || ""]] + } + } + } }, { fieldtype: 'Section Break' From 7b45ae1f2dbc76db0fc5d72c8791161879ce5640 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 19 Mar 2020 10:58:41 +0530 Subject: [PATCH 099/137] fix: Multiple fixes during pre-release testing (#20985) --- .../doctype/journal_entry/journal_entry.py | 8 +- .../doctype/vehicle_log/test_vehicle_log.py | 7 +- erpnext/hr/doctype/vehicle_log/vehicle_log.js | 26 --- .../hr/doctype/vehicle_log/vehicle_log.json | 9 +- erpnext/hr/doctype/vehicle_log/vehicle_log.py | 54 ++--- .../vehicle_service/vehicle_service.json | 194 +++++------------- .../bom_stock_calculated.py | 4 +- 7 files changed, 84 insertions(+), 218 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 04c5c9ec679..1a530c75395 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -456,8 +456,10 @@ class JournalEntry(AccountsController): def set_print_format_fields(self): bank_amount = party_amount = total_amount = 0.0 currency = bank_account_currency = party_account_currency = pay_to_recd_from= None + party_type = None for d in self.get('accounts'): if d.party_type in ['Customer', 'Supplier'] and d.party: + party_type = d.party_type if not pay_to_recd_from: pay_to_recd_from = d.party @@ -469,9 +471,9 @@ class JournalEntry(AccountsController): bank_amount += (d.debit_in_account_currency or d.credit_in_account_currency) bank_account_currency = d.account_currency - if pay_to_recd_from: - self.pay_to_recd_from = frappe.db.get_value(d.party_type, pay_to_recd_from, - "customer_name" if d.party_type=="Customer" else "supplier_name") + if party_type and pay_to_recd_from: + self.pay_to_recd_from = frappe.db.get_value(party_type, pay_to_recd_from, + "customer_name" if party_type=="Customer" else "supplier_name") if bank_amount: total_amount = bank_amount currency = bank_account_currency diff --git a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py index 3770da73fcf..e9dc7764f7b 100644 --- a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py @@ -6,11 +6,14 @@ from __future__ import unicode_literals import frappe import unittest from frappe.utils import nowdate,flt, cstr,random_string -# test_records = frappe.get_test_records('Vehicle Log') + class TestVehicleLog(unittest.TestCase): def test_make_vehicle_log_and_syncing_of_odometer_value(self): - employee_id=frappe.db.sql("""select name from `tabEmployee` order by modified desc limit 1""")[0][0] + employee_id = frappe.db.sql("""select name from `tabEmployee` where status='Active' order by modified desc limit 1""") + employee_id = employee_id[0][0] if employee_id else None + license_plate = get_vehicle(employee_id) + vehicle_log = frappe.get_doc({ "doctype": "Vehicle Log", "license_plate": cstr(license_plate), diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.js b/erpnext/hr/doctype/vehicle_log/vehicle_log.js index bdb37d2b734..6f3a0dc40eb 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.js +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.js @@ -3,11 +3,6 @@ frappe.ui.form.on("Vehicle Log", { refresh: function(frm) { - - if(frm.doc.license_plate && frm.doc.__islocal){ - frm.events.set_vehicle_details(frm); - } - if(frm.doc.docstatus == 1) { frm.add_custom_button(__('Expense Claim'), function() { frm.events.expense_claim(frm); @@ -16,27 +11,6 @@ frappe.ui.form.on("Vehicle Log", { } }, - license_plate: function(frm) { - if(frm.doc.license_plate){ - frm.events.set_vehicle_details(frm); - } - }, - - set_vehicle_details: function(frm) { - frappe.call({ - method: "erpnext.hr.doctype.vehicle_log.vehicle_log.get_make_model", - args: { - license_plate: frm.doc.license_plate - }, - callback: function(r) { - frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "make", r.message[0]); - frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "model", r.message[1]); - frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "last_odometer", r.message[2]); - frappe.model.set_value(cur_frm.doctype, cur_frm.docname, "employee", r.message[3]); - } - }); - }, - expense_claim: function(frm){ frappe.call({ method: "erpnext.hr.doctype.vehicle_log.vehicle_log.make_expense_claim", diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.json b/erpnext/hr/doctype/vehicle_log/vehicle_log.json index 52effffc064..619e295ebe8 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.json +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.json @@ -1,5 +1,4 @@ { - "actions": [], "autoname": "naming_series:", "creation": "2016-09-03 14:14:51.788550", "doctype": "DocType", @@ -56,6 +55,8 @@ "reqd": 1 }, { + "fetch_from": "license_plate.employee", + "fetch_if_empty": 1, "fieldname": "employee", "fieldtype": "Link", "in_list_view": 1, @@ -73,11 +74,13 @@ "fieldtype": "Column Break" }, { + "fetch_from": "license_plate.model", "fieldname": "model", "fieldtype": "Read Only", "label": "Model" }, { + "fetch_from": "license_plate.make", "fieldname": "make", "fieldtype": "Read Only", "label": "Make" @@ -152,6 +155,7 @@ "read_only": 1 }, { + "fetch_from": "license_plate.last_odometer", "fieldname": "last_odometer", "fieldtype": "Int", "label": "last Odometer Value ", @@ -164,8 +168,7 @@ } ], "is_submittable": 1, - "links": [], - "modified": "2020-01-28 12:43:34.419647", + "modified": "2020-03-18 16:45:45.060761", "modified_by": "Administrator", "module": "HR", "name": "Vehicle Log", diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.py b/erpnext/hr/doctype/vehicle_log/vehicle_log.py index 12cc1dd03a6..8affab2a18d 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.py @@ -12,18 +12,7 @@ from frappe.model.document import Document class VehicleLog(Document): def validate(self): if flt(self.odometer) < flt(self.last_odometer): - frappe.throw(_("Current Odometer reading entered should be greater than initial Vehicle Odometer {0}").format(self.last_odometer)) - for service_detail in self.service_detail: - if (service_detail.service_item or service_detail.type or service_detail.frequency or service_detail.expense_amount): - if not (service_detail.service_item and service_detail.type and service_detail.frequency and service_detail.expense_amount): - frappe.throw(_("Service Item,Type,frequency and expense amount are required")) - - def before_insert(self): - model_details = get_make_model(self.license_plate) - self.make = model_details[0] - self.model = model_details[1] - self.last_odometer = model_details[2] - self.employee = model_details[3] + frappe.throw(_("Current Odometer Value should be greater than Last Odometer Value {0}").format(self.last_odometer)) def on_submit(self): frappe.db.set_value("Vehicle", self.license_plate, "last_odometer", self.odometer) @@ -34,35 +23,26 @@ class VehicleLog(Document): updated_odometer_value = int(frappe.db.get_value("Vehicle", self.license_plate, "last_odometer")) - distance_travelled frappe.db.set_value("Vehicle", self.license_plate, "last_odometer", updated_odometer_value) -@frappe.whitelist() -def get_make_model(license_plate): - vehicle=frappe.get_doc("Vehicle",license_plate) - return (vehicle.make, vehicle.model, vehicle.last_odometer, vehicle.employee) - @frappe.whitelist() def make_expense_claim(docname): - def check_exp_claim_exists(): - exp_claim = frappe.db.sql("""select name from `tabExpense Claim` where vehicle_log=%s""",vehicle_log.name) - return exp_claim[0][0] if exp_claim else "" - def calc_service_exp(): - total_exp_amt=0 - exp_claim = check_exp_claim_exists() - if exp_claim: - frappe.throw(_("Expense Claim {0} already exists for the Vehicle Log").format(exp_claim)) - for serdetail in vehicle_log.service_detail: - total_exp_amt = total_exp_amt + serdetail.expense_amount - return total_exp_amt + expense_claim = frappe.db.exists("Expense Claim", {"vehicle_log": docname}) + if expense_claim: + frappe.throw(_("Expense Claim {0} already exists for the Vehicle Log").format(expense_claim)) vehicle_log = frappe.get_doc("Vehicle Log", docname) + service_expense = sum([flt(d.expense_amount) for d in vehicle_log.service_detail]) + + claim_amount = service_expense + flt(vehicle_log.price) + if not claim_amount: + frappe.throw(_("No additional expenses has been added")) + exp_claim = frappe.new_doc("Expense Claim") - exp_claim.employee=vehicle_log.employee - exp_claim.vehicle_log=vehicle_log.name - exp_claim.remark=_("Expense Claim for Vehicle Log {0}").format(vehicle_log.name) - fuel_price=vehicle_log.price - total_claim_amt=calc_service_exp() + fuel_price - exp_claim.append("expenses",{ - "expense_date":vehicle_log.date, - "description":_("Vehicle Expenses"), - "amount":total_claim_amt + exp_claim.employee = vehicle_log.employee + exp_claim.vehicle_log = vehicle_log.name + exp_claim.remark = _("Expense Claim for Vehicle Log {0}").format(vehicle_log.name) + exp_claim.append("expenses", { + "expense_date": vehicle_log.date, + "description": _("Vehicle Expenses"), + "amount": claim_amount }) return exp_claim.as_dict() diff --git a/erpnext/hr/doctype/vehicle_service/vehicle_service.json b/erpnext/hr/doctype/vehicle_service/vehicle_service.json index 7d9d0df44cc..e0bce2b6eec 100644 --- a/erpnext/hr/doctype/vehicle_service/vehicle_service.json +++ b/erpnext/hr/doctype/vehicle_service/vehicle_service.json @@ -1,153 +1,57 @@ { - "allow_copy": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2016-09-03 19:20:14.561962", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, + "creation": "2016-09-03 19:20:14.561962", + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "service_item", + "type", + "frequency", + "expense_amount" + ], "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "service_item", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Service Item", - "length": 0, - "no_copy": 0, - "options": "\nBrake Oil\nBrake Pad\nClutch Plate\nEngine Oil\nOil Change\nWheels", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "service_item", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Service Item", + "options": "\nBrake Oil\nBrake Pad\nClutch Plate\nEngine Oil\nOil Change\nWheels", + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "type", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Type", - "length": 0, - "no_copy": 0, - "options": "\nInspection\nService\nChange", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "type", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Type", + "options": "\nInspection\nService\nChange", + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "frequency", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Frequency", - "length": 0, - "no_copy": 0, - "options": "\nMileage\nMonthly\nQuarterly\nHalf Yearly\nYearly", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "frequency", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Frequency", + "options": "\nMileage\nMonthly\nQuarterly\nHalf Yearly\nYearly", + "reqd": 1 + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "expense_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Expense", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "fieldname": "expense_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Expense", + "reqd": 1 } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2017-01-09 11:10:29.476907", - "modified_by": "Administrator", - "module": "HR", - "name": "Vehicle Service", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "istable": 1, + "modified": "2020-03-18 16:49:46.645004", + "modified_by": "Administrator", + "module": "HR", + "name": "Vehicle Service", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py index f7b407b7922..c1204d36152 100644 --- a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py +++ b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py @@ -26,8 +26,8 @@ def get_report_data(last_pur_price, reqd_qty, row, manufacture_details): to_build = row.to_build if row.to_build > 0 else 0 diff_qty = to_build - reqd_qty return [row.item_code, row.description, - comma_and(manufacture_details.get(row.item_code, {}).get('manufacturer', []), add_quotes=False), - comma_and(manufacture_details.get(row.item_code, {}).get('manufacturer_part', []), add_quotes=False), + comma_and(manufacture_details.get(row.item_code, {}).get('manufacturer', [])), + comma_and(manufacture_details.get(row.item_code, {}).get('manufacturer_part', [])), row.actual_qty, str(to_build), reqd_qty, diff_qty, last_pur_price] From 71e9f23d7755c0a4243be13a5932c1d7c2e26fde Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Thu, 19 Mar 2020 11:00:55 +0530 Subject: [PATCH 100/137] fix: Update is_tree field in Tree doctypes (#20982) --- erpnext/accounts/doctype/account/account.json | 6 +- .../doctype/cost_center/cost_center.json | 4 +- erpnext/assets/doctype/location/location.json | 4 +- .../assessment_group/assessment_group.json | 335 +++---------- .../healthcare_service_unit.json | 406 ++------------- erpnext/hr/doctype/department/department.json | 472 ++---------------- erpnext/projects/doctype/task/task.json | 6 +- .../quality_procedure/quality_procedure.json | 6 +- erpnext/setup/doctype/company/company.json | 6 +- .../customer_group/customer_group.json | 4 +- .../setup/doctype/item_group/item_group.json | 4 +- .../doctype/sales_person/sales_person.json | 4 +- .../supplier_group/supplier_group.json | 384 ++------------ .../setup/doctype/territory/territory.json | 4 +- .../stock/doctype/warehouse/warehouse.json | 4 +- 15 files changed, 226 insertions(+), 1423 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.json b/erpnext/accounts/doctype/account/account.json index 64efc2775a6..6a1183546f3 100644 --- a/erpnext/accounts/doctype/account/account.json +++ b/erpnext/accounts/doctype/account/account.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_copy": 1, "allow_import": 1, "creation": "2013-01-30 12:49:46", @@ -196,10 +197,13 @@ ], "icon": "fa fa-money", "idx": 1, - "modified": "2019-10-10 19:10:02.967554", + "is_tree": 1, + "links": [], + "modified": "2020-03-18 18:26:03.992861", "modified_by": "Administrator", "module": "Accounts", "name": "Account", + "nsm_parent_field": "parent_account", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/accounts/doctype/cost_center/cost_center.json b/erpnext/accounts/doctype/cost_center/cost_center.json index 976f05ad637..126aa543185 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.json +++ b/erpnext/accounts/doctype/cost_center/cost_center.json @@ -124,11 +124,13 @@ ], "icon": "fa fa-money", "idx": 1, + "is_tree": 1, "links": [], - "modified": "2020-01-28 13:50:23.430434", + "modified": "2020-03-18 18:26:01.540170", "modified_by": "Administrator", "module": "Accounts", "name": "Cost Center", + "nsm_parent_field": "parent_cost_center", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/assets/doctype/location/location.json b/erpnext/assets/doctype/location/location.json index 5ecc72ab913..58f59701960 100644 --- a/erpnext/assets/doctype/location/location.json +++ b/erpnext/assets/doctype/location/location.json @@ -139,12 +139,14 @@ "read_only": 1 } ], + "is_tree": 1, "links": [], - "modified": "2020-01-28 13:52:22.513425", + "modified": "2020-03-18 18:25:59.283057", "modified_by": "Administrator", "module": "Assets", "name": "Location", "name_case": "Title Case", + "nsm_parent_field": "parent_location", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/education/doctype/assessment_group/assessment_group.json b/erpnext/education/doctype/assessment_group/assessment_group.json index 56917d20526..a341938a101 100644 --- a/erpnext/education/doctype/assessment_group/assessment_group.json +++ b/erpnext/education/doctype/assessment_group/assessment_group.json @@ -1,274 +1,91 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:assessment_group_name", - "beta": 0, - "creation": "2016-08-04 04:42:48.319388", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:assessment_group_name", + "creation": "2016-08-04 04:42:48.319388", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "assessment_group_name", + "is_group", + "section_break_2", + "parent_assessment_group", + "lft", + "rgt", + "old_parent" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "assessment_group_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Assessment Group Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "assessment_group_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Assessment Group Name", + "reqd": 1, + "unique": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "is_group", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Is Group", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "is_group", + "fieldtype": "Check", + "label": "Is Group" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_2", - "fieldtype": "Section Break", - "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, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "section_break_2", + "fieldtype": "Section Break", + "hidden": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "parent_assessment_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Parent Assessment Group", - "length": 0, - "no_copy": 0, - "options": "Assessment Group", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "parent_assessment_group", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Parent Assessment Group", + "options": "Assessment Group", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lft", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "lft", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "lft", + "fieldtype": "Int", + "label": "lft" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "rgt", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "rgt", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "rgt", + "fieldtype": "Int", + "label": "rgt" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "old_parent", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "old_parent", - "length": 0, - "no_copy": 0, - "options": "Assessment Group", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "fieldname": "old_parent", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "old_parent", + "options": "Assessment Group" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-11-10 19:09:25.366400", - "modified_by": "Administrator", - "module": "Education", - "name": "Assessment Group", - "name_case": "", - "owner": "Administrator", + ], + "is_tree": 1, + "links": [], + "modified": "2020-03-18 18:26:07.834596", + "modified_by": "Administrator", + "module": "Education", + "name": "Assessment Group", + "nsm_parent_field": "parent_assessment_group", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Academics User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Academics User", + "share": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Education", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0 + ], + "quick_entry": 1, + "restrict_to_domain": "Education", + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json index 6e92455404f..15d976530b2 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json +++ b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json @@ -1,542 +1,206 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "field:healthcare_service_unit_name", "beta": 1, "creation": "2016-09-21 13:48:14.731437", - "custom": 0, "description": "Healthcare Service Unit", - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "healthcare_service_unit_name", + "parent_healthcare_service_unit", + "is_group", + "service_unit_type", + "allow_appointments", + "overlap_appointments", + "inpatient_occupancy", + "occupancy_status", + "warehouse", + "company", + "lft", + "rgt", + "old_parent" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "healthcare_service_unit_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, "in_global_search": 1, "in_list_view": 1, - "in_standard_filter": 0, "label": "Service Unit", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, "unique": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "fieldname": "parent_healthcare_service_unit", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Parent Service Unit", - "length": 0, - "no_copy": 0, - "options": "Healthcare Service Unit", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Healthcare Service Unit" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "default": "0", "depends_on": "eval:doc.inpatient_occupancy != 1 && doc.allow_appointments != 1", "fieldname": "is_group", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Is Group", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Is Group" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "depends_on": "eval:doc.is_group != 1", "fieldname": "service_unit_type", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Service Unit Type", - "length": 0, - "no_copy": 0, - "options": "Healthcare Service Unit Type", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Healthcare Service Unit Type" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "default": "0", "depends_on": "eval:doc.is_group != 1 && doc.inpatient_occupancy != 1", "fetch_from": "service_unit_type.allow_appointments", "fieldname": "allow_appointments", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Allow Appointments", - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "depends_on": "eval:doc.is_group != 1 && doc.allow_appointments == 1 && doc.inpatient_occupany != 1", "fetch_from": "service_unit_type.overlap_appointments", "fieldname": "overlap_appointments", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Allow Overlap", - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "default": "0", "depends_on": "eval:doc.allow_appointments != 1 && doc.is_group != 1", "fetch_from": "service_unit_type.inpatient_occupancy", "fieldname": "inpatient_occupancy", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Inpatient Occupancy", - "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": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", "depends_on": "eval:doc.inpatient_occupancy == 1", "fieldname": "occupancy_status", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Occupancy Status", - "length": 0, "no_copy": 1, "options": "Vacant\nOccupied", - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "depends_on": "eval:doc.is_group != 1", "fieldname": "warehouse", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Warehouse", - "length": 0, "no_copy": 1, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Warehouse" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "company", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Company", - "length": 0, - "no_copy": 0, "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, "remember_last_selected_value": 1, - "report_hide": 0, "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "lft", "fieldtype": "Int", "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": "lft", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "rgt", "fieldtype": "Int", "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": "rgt", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "old_parent", "fieldtype": "Link", "hidden": 1, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Old Parent", - "length": 0, "no_copy": 1, "options": "Healthcare Service Unit", - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-10-04 21:09:52.261882", + "is_tree": 1, + "links": [], + "modified": "2020-03-18 18:26:06.360941", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare Service Unit", - "name_case": "", + "nsm_parent_field": "parent_healthcare_service_unit", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Nursing User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 + "share": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Healthcare Administrator", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, - "delete": 0, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Physician", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 } ], "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, "restrict_to_domain": "Healthcare", "search_fields": "healthcare_service_unit_name", - "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", "title_field": "healthcare_service_unit_name", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/hr/doctype/department/department.json b/erpnext/hr/doctype/department/department.json index 3b400ce8d76..2de391efaaa 100644 --- a/erpnext/hr/doctype/department/department.json +++ b/erpnext/hr/doctype/department/department.json @@ -1,569 +1,177 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, + "actions": [], "allow_import": 1, "allow_rename": 1, - "autoname": "", - "beta": 0, "creation": "2013-02-05 11:48:26", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", - "editable_grid": 0, + "engine": "InnoDB", + "field_order": [ + "department_name", + "parent_department", + "company", + "is_group", + "disabled", + "section_break_4", + "leave_block_list", + "leave_section", + "leave_approvers", + "expense_section", + "expense_approvers", + "lft", + "rgt", + "old_parent" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "department_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Department", - "length": 0, - "no_copy": 0, "oldfieldname": "department_name", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "parent_department", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Parent Department", - "length": 0, - "no_copy": 0, - "options": "Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Department" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "company", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, "in_standard_filter": 1, "label": "Company", - "length": 0, - "no_copy": 0, "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "is_group", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Is Group", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Is Group" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, + "default": "0", "fieldname": "disabled", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Disabled", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Disabled" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "section_break_4", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "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, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Leave Block List", - "length": 0, - "no_copy": 0, - "options": "Leave Block List", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Leave Block List" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "leave_section", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Leave Approvers", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Leave Approvers" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "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, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Leave Approver", - "length": 0, - "no_copy": 0, - "options": "Department Approver", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Department Approver" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "expense_section", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Expense Approvers", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Expense Approvers" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "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, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Expense Approver", - "length": 0, - "no_copy": 0, - "options": "Department Approver", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Department Approver" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "lft", "fieldtype": "Int", "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": "lft", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", "print_hide": 1, - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "rgt", "fieldtype": "Int", "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": "rgt", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", "print_hide": 1, - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, "fieldname": "old_parent", "fieldtype": "Data", "hidden": 1, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Old Parent", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "print_hide": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "icon": "fa fa-sitemap", "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-06-25 18:43:05.550387", + "is_tree": 1, + "links": [], + "modified": "2020-03-18 18:26:05.966022", "modified_by": "Administrator", "module": "HR", "name": "Department", + "nsm_parent_field": "parent_department", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "HR User", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Academics User", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, "import": 1, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "HR Manager", "set_user_permissions": 1, "share": 1, - "submit": 0, "write": 1 } ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, "show_name_in_global_search": 1, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json index 794d8161d2f..ce0dbd179ce 100644 --- a/erpnext/projects/doctype/task/task.json +++ b/erpnext/projects/doctype/task/task.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "autoname": "TASK-.YYYY.-.#####", "creation": "2013-01-29 19:25:50", @@ -361,11 +362,14 @@ ], "icon": "fa fa-check", "idx": 1, + "is_tree": 1, + "links": [], "max_attachments": 5, - "modified": "2019-09-10 13:46:24.631754", + "modified": "2020-03-18 18:26:04.788061", "modified_by": "Administrator", "module": "Projects", "name": "Task", + "nsm_parent_field": "parent_task", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json index 472b75103cc..e44e0733967 100644 --- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json +++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "format:PRC-{quality_procedure_name}", "creation": "2018-10-06 00:06:29.756804", "doctype": "DocType", @@ -69,10 +70,13 @@ "reqd": 1 } ], - "modified": "2019-08-05 13:09:29.945082", + "is_tree": 1, + "links": [], + "modified": "2020-03-18 18:26:05.511984", "modified_by": "Administrator", "module": "Quality Management", "name": "Quality Procedure", + "nsm_parent_field": "parent_quality_procedure", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index dd602eca103..5ce51a6e8d9 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "field:company_name", @@ -725,10 +726,13 @@ "icon": "fa fa-building", "idx": 1, "image_field": "company_logo", - "modified": "2019-11-22 13:04:47.470768", + "is_tree": 1, + "links": [], + "modified": "2020-03-18 18:26:03.145312", "modified_by": "Administrator", "module": "Setup", "name": "Company", + "nsm_parent_field": "parent_company", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/setup/doctype/customer_group/customer_group.json b/erpnext/setup/doctype/customer_group/customer_group.json index 7fa242ae19d..82d5f7a3f73 100644 --- a/erpnext/setup/doctype/customer_group/customer_group.json +++ b/erpnext/setup/doctype/customer_group/customer_group.json @@ -137,11 +137,13 @@ ], "icon": "fa fa-sitemap", "idx": 1, + "is_tree": 1, "links": [], - "modified": "2020-01-28 13:49:23.961708", + "modified": "2020-03-18 18:26:02.536305", "modified_by": "Administrator", "module": "Setup", "name": "Customer Group", + "nsm_parent_field": "parent_customer_group", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/setup/doctype/item_group/item_group.json b/erpnext/setup/doctype/item_group/item_group.json index 36e3e68ef43..849fb6fd911 100644 --- a/erpnext/setup/doctype/item_group/item_group.json +++ b/erpnext/setup/doctype/item_group/item_group.json @@ -185,13 +185,15 @@ "icon": "fa fa-sitemap", "idx": 1, "image_field": "image", + "is_tree": 1, "links": [], "max_attachments": 3, - "modified": "2020-01-28 13:51:05.456014", + "modified": "2020-03-18 18:25:59.979083", "modified_by": "Administrator", "module": "Setup", "name": "Item Group", "name_case": "Title Case", + "nsm_parent_field": "parent_item_group", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/setup/doctype/sales_person/sales_person.json b/erpnext/setup/doctype/sales_person/sales_person.json index b05365d2ca9..d7a9d5dfba1 100644 --- a/erpnext/setup/doctype/sales_person/sales_person.json +++ b/erpnext/setup/doctype/sales_person/sales_person.json @@ -143,11 +143,13 @@ ], "icon": "icon-user", "idx": 1, + "is_tree": 1, "links": [], - "modified": "2020-01-28 13:50:31.891050", + "modified": "2020-03-18 18:26:01.076203", "modified_by": "Administrator", "module": "Setup", "name": "Sales Person", + "nsm_parent_field": "parent_sales_person", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.json b/erpnext/setup/doctype/supplier_group/supplier_group.json index 5c413341935..b7989d4ffad 100644 --- a/erpnext/setup/doctype/supplier_group/supplier_group.json +++ b/erpnext/setup/doctype/supplier_group/supplier_group.json @@ -1,481 +1,165 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "field:supplier_group_name", - "beta": 0, "creation": "2013-01-10 16:34:24", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", - "editable_grid": 0, + "engine": "InnoDB", + "field_order": [ + "supplier_group_name", + "parent_supplier_group", + "is_group", + "section_credit_limit", + "payment_terms", + "default_payable_account", + "accounts", + "lft", + "rgt", + "old_parent" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "supplier_group_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Supplier Group Name", - "length": 0, - "no_copy": 0, "oldfieldname": "supplier_type", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, "unique": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, "fieldname": "parent_supplier_group", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Parent Supplier Group", - "length": 0, - "no_copy": 0, - "options": "Supplier Group", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Supplier Group" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, "bold": 1, - "collapsible": 0, - "columns": 0, + "default": "0", "fieldname": "is_group", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Is Group", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Is Group" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, "collapsible": 1, - "columns": 0, "fieldname": "section_credit_limit", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Credit Limit", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Credit Limit" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "payment_terms", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Default Payment Terms Template", - "length": 0, - "no_copy": 0, - "options": "Payment Terms Template", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Payment Terms Template" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "default_payable_account", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Payable Account", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Default Payable Account" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:!doc.__islocal", "description": "Mention if non-standard receivable account applicable", "fieldname": "accounts", "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Accounts", - "length": 0, - "no_copy": 0, - "options": "Party Account", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Party Account" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "lft", "fieldtype": "Int", "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": "lft", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "rgt", "fieldtype": "Int", "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": "rgt", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "old_parent", "fieldtype": "Link", "hidden": 1, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Old Parent", - "length": 0, "no_copy": 1, "options": "Supplier Group", - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "icon": "fa fa-flag", "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-29 06:25:57.589824", + "is_tree": 1, + "links": [], + "modified": "2020-03-18 18:26:07.179330", "modified_by": "Administrator", "module": "Setup", "name": "Supplier Group", + "nsm_parent_field": "parent_supplier_group", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, - "role": "Purchase Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "role": "Purchase Manager" }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, - "role": "Purchase User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "role": "Purchase User" }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, "import": 1, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Purchase Master Manager", "set_user_permissions": 1, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, "permlevel": 1, - "print": 0, "read": 1, - "report": 0, "role": "Purchase Master Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, "permlevel": 1, - "print": 0, "read": 1, - "report": 0, - "role": "Purchase Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "role": "Purchase Manager" }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, "permlevel": 1, - "print": 0, "read": 1, - "report": 0, - "role": "Purchase User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "role": "Purchase User" } ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, "show_name_in_global_search": 1, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/erpnext/setup/doctype/territory/territory.json b/erpnext/setup/doctype/territory/territory.json index 91a3dda2bb0..4277fe75ec4 100644 --- a/erpnext/setup/doctype/territory/territory.json +++ b/erpnext/setup/doctype/territory/territory.json @@ -121,12 +121,14 @@ ], "icon": "fa fa-map-marker", "idx": 1, + "is_tree": 1, "links": [], - "modified": "2020-01-28 13:49:31.905800", + "modified": "2020-03-18 18:26:02.055750", "modified_by": "Administrator", "module": "Setup", "name": "Territory", "name_case": "Title Case", + "nsm_parent_field": "parent_territory", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/stock/doctype/warehouse/warehouse.json b/erpnext/stock/doctype/warehouse/warehouse.json index 2bf1ed89838..0606d0bdc64 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.json +++ b/erpnext/stock/doctype/warehouse/warehouse.json @@ -228,11 +228,13 @@ ], "icon": "fa fa-building", "idx": 1, + "is_tree": 1, "links": [], - "modified": "2020-01-28 13:50:59.368846", + "modified": "2020-03-18 18:26:00.479541", "modified_by": "Administrator", "module": "Stock", "name": "Warehouse", + "nsm_parent_field": "parent_warehouse", "owner": "Administrator", "permissions": [ { From 8c56f8595e21e96a82f574bca46bd252f351e4af Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Thu, 19 Mar 2020 11:03:14 +0530 Subject: [PATCH 101/137] fix: Unable to submit landed cost voucher (#20978) --- .../stock/doctype/landed_cost_voucher/landed_cost_voucher.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index 7df40fb02cd..d97b699a0f3 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -104,7 +104,6 @@ class LandedCostVoucher(Document): def update_landed_cost(self): for d in self.get("purchase_receipts"): doc = frappe.get_doc(d.receipt_document_type, d.receipt_document) - # check if there are {qty} assets created and linked to this receipt document self.validate_asset_qty_and_status(d.receipt_document_type, doc) @@ -123,6 +122,8 @@ class LandedCostVoucher(Document): # update latest valuation rate in serial no self.update_rate_in_serial_no_for_non_asset_items(doc) + for d in self.get("purchase_receipts"): + doc = frappe.get_doc(d.receipt_document_type, d.receipt_document) # update stock & gl entries for cancelled state of PR doc.docstatus = 2 doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) From 4c4a1aa56da55c6bc435c60795b60a12d5c0fb49 Mon Sep 17 00:00:00 2001 From: Rohan Date: Thu, 19 Mar 2020 13:10:26 +0530 Subject: [PATCH 102/137] fix: allow target warehouses to be changed for work order stock entries --- erpnext/stock/doctype/stock_entry/stock_entry.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 56cb3f06b94..0710e551049 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -294,13 +294,8 @@ class StockEntry(StockController): if validate_for_manufacture: if d.bom_no: d.s_warehouse = None - if not d.t_warehouse: frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx)) - - elif self.pro_doc and (cstr(d.t_warehouse) != self.pro_doc.fg_warehouse and cstr(d.t_warehouse) != self.pro_doc.scrap_warehouse): - frappe.throw(_("Target warehouse in row {0} must be same as Work Order").format(d.idx)) - else: d.t_warehouse = None if not d.s_warehouse: From 794064db9fb135d354aa06d3eeaa7235fb5d9271 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 19 Mar 2020 14:44:16 +0530 Subject: [PATCH 103/137] fix: stock entry qty must be positive --- erpnext/stock/doctype/stock_entry/stock_entry.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 56cb3f06b94..a6da3d306b4 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -177,6 +177,10 @@ class StockEntry(StockController): stock_items = self.get_stock_items() serialized_items = self.get_serialized_items() for item in self.get("items"): + if item.qty and item.qty < 0: + frappe.throw(_("Row {0}: The item {1}, quantity must be positive number") + .format(item.idx, frappe.bold(item.item_code))) + if item.item_code not in stock_items: frappe.throw(_("{0} is not a stock Item").format(item.item_code)) From e53e96f01bcb033b511bf9a2c7ee15fd8c0d878f Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Fri, 20 Mar 2020 13:57:30 +0530 Subject: [PATCH 104/137] chore: pass traceback and error message as kwargs fixes issue where the system tries to generate an error log but fails with the following error: Traceback (most recent call last): File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/setup/doctype/company/company.py", line 421, in install_country_fixtures frappe.get_attr(module_name)(company_doc, False) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/regional/india/setup.py", line 17, in setup make_fixtures(company) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/regional/india/setup.py", line 523, in make_fixtures set_tax_withholding_category(company) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/regional/india/setup.py", line 543, in set_tax_withholding_category fiscal_year = get_fiscal_year(today(), company=company)[0] File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/accounts/utils.py", line 24, in get_fiscal_year return get_fiscal_years(date, fiscal_year, label, verbose, company, as_dict=as_dict)[0] File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/accounts/utils.py", line 80, in get_fiscal_years raise FiscalYearError(error_msg) erpnext.accounts.utils.FiscalYearError: Date 20-03-2020 not in any active Fiscal Year. During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/app.py", line 62, in application response = frappe.api.handle() File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/api.py", line 55, in handle return frappe.handler.handle() File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/handler.py", line 22, in handle data = execute_cmd(cmd) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/handler.py", line 61, in execute_cmd return frappe.call(method, **frappe.form_dict) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/__init__.py", line 1054, in call return fn(*args, **newargs) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/desk/form/save.py", line 22, in savedocs doc.save() File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 273, in save return self._save(*args, **kwargs) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 296, in _save self.insert() File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 260, in insert self.run_post_save_methods() File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 926, in run_post_save_methods self.run_method("on_update") File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 794, in run_method out = Document.hook(fn)(self, *args, **kwargs) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 1065, in composer return composed(self, method, *args, **kwargs) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 1048, in runner add_to_return_value(self, fn(self, *args, **kwargs)) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 788, in fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/setup/doctype/company/company.py", line 107, in on_update install_country_fixtures(self.name) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/setup/doctype/company/company.py", line 423, in install_country_fixtures frappe.log_error(str(e), frappe.get_traceback()) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/__init__.py", line 1524, in log_error method=title)).insert(ignore_permissions=True) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 231, in insert self._validate() File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/document.py", line 463, in _validate self._validate_length() File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/base_document.py", line 583, in _validate_length self.throw_length_exceeded_error(df, max_length, value) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/model/base_document.py", line 599, in throw_length_exceeded_error .format(reference, _(df.label), max_length, value), frappe.CharacterLengthExceededError, title=_('Value too big')) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/__init__.py", line 377, in throw msgprint(msg, raise_exception=exc, title=title, indicator='red', is_minimizable=is_minimizable) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/__init__.py", line 356, in msgprint _raise_exception() File "/home/frappe/benches/bench-version-12-2020-03-19/apps/frappe/frappe/__init__.py", line 316, in _raise_exception raise raise_exception(msg) frappe.exceptions.CharacterLengthExceededError: Error Log f2cbb8c0f2: 'Title' (Traceback (most recent call last): File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/setup/doctype/company/company.py", line 421, in install_country_fixtures frappe.get_attr(module_name)(company_doc, False) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/regional/india/setup.py", line 17, in setup make_fixtures(company) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/regional/india/setup.py", line 523, in make_fixtures set_tax_withholding_category(company) File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/regional/india/setup.py", line 543, in set_tax_withholding_category fiscal_year = get_fiscal_year(today(), company=company)[0] File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/accounts/utils.py", line 24, in get_fiscal_year return get_fiscal_years(date, fiscal_year, label, verbose, company, as_dict=as_dict)[0] File "/home/frappe/benches/bench-version-12-2020-03-19/apps/erpnext/erpnext/accounts/utils.py", line 80, in get_fiscal_years raise FiscalYearError(error_msg) erpnext.accounts.utils.FiscalYearError: Date 20-03-2020 not in any active Fiscal Year. ) will get truncated, as max characters allowed is 140 Signed-off-by: Chinmay D. Pai --- erpnext/setup/doctype/company/company.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index c3fd3566578..bc27f40f560 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -420,7 +420,7 @@ def install_country_fixtures(company): module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(company_doc.country)) frappe.get_attr(module_name)(company_doc, False) except Exception as e: - frappe.log_error(str(e), frappe.get_traceback()) + frappe.log_error(title=str(e), message=frappe.get_traceback()) frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(company_doc.country))) @@ -590,4 +590,4 @@ def get_default_company_address(name, sort_key='is_primary_address', existing_ad if out: return sorted(out, key = functools.cmp_to_key(lambda x,y: cmp(y[1], x[1])))[0][0] else: - return None \ No newline at end of file + return None From e2bb2593db815aaa78558f7830cb288910d9ae4c Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 20 Mar 2020 12:51:16 +0530 Subject: [PATCH 105/137] fix: Add currency in options of Opportunity Amount - To show currect symbol in list view --- erpnext/crm/doctype/opportunity/opportunity.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 66e3ca48dd2..979e4c7a67f 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "naming_series:", @@ -208,7 +209,8 @@ { "fieldname": "opportunity_amount", "fieldtype": "Currency", - "label": "Opportunity Amount" + "label": "Opportunity Amount", + "options": "currency" }, { "default": "0", @@ -412,7 +414,8 @@ ], "icon": "fa fa-info-sign", "idx": 195, - "modified": "2019-09-30 12:58:37.385400", + "links": [], + "modified": "2020-03-20 12:28:45.228994", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", From 20ab2c1e20a48a08bf32de9324ae45af008c148d Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 22 Mar 2020 21:50:22 +0530 Subject: [PATCH 106/137] fix: Remove quick entry from accouting dimensions --- .../accounting_dimension.js | 6 ------ .../accounting_dimension.json | 17 +++++++++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js index a36f4214d7c..3c12f85f938 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js @@ -48,12 +48,6 @@ frappe.ui.form.on('Accounting Dimension', { frm.set_value('label', frm.doc.document_type); frm.set_value('fieldname', frappe.model.scrub(frm.doc.document_type)); - if (frm.is_new()){ - let row = frappe.model.add_child(frm.doc, "Accounting Dimension Detail", "dimension_defaults"); - row.reference_document = frm.doc.document_type; - frm.refresh_fields("dimension_defaults"); - } - frappe.db.get_value('Accounting Dimension', {'document_type': frm.doc.document_type}, 'document_type', (r) => { if (r && r.document_type) { frm.set_df_property('document_type', 'description', "Document type is already set as dimension"); diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json index cf6dc7a8fa5..cf55d554fb3 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "field:label", "creation": "2019-05-04 18:13:37.002352", "doctype": "DocType", @@ -46,7 +47,8 @@ "options": "Accounting Dimension Detail" } ], - "modified": "2019-07-17 16:49:31.134385", + "links": [], + "modified": "2020-03-22 20:34:39.805728", "modified_by": "Administrator", "module": "Accounts", "name": "Accounting Dimension", @@ -63,9 +65,20 @@ "role": "System Manager", "share": 1, "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "share": 1, + "write": 1 } ], - "quick_entry": 1, "sort_field": "modified", "sort_order": "ASC", "track_changes": 1 From b05922026d6da9fa1bc6b421809641730400da89 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 23 Mar 2020 16:31:39 +0530 Subject: [PATCH 107/137] feat: import supplier invoices --- erpnext/patches.txt | 1 + .../v12_0/set_permission_einvoicing.py | 15 + .../import_supplier_invoice/__init__.py | 0 .../import_supplier_invoice.js | 46 ++ .../import_supplier_invoice.json | 105 +++++ .../import_supplier_invoice.py | 402 ++++++++++++++++++ .../test_import_supplier_invoice.py | 10 + erpnext/regional/italy/setup.py | 25 ++ erpnext/regional/italy/utils.py | 2 + .../purchase_einvoice/__init__.py | 0 .../purchase_einvoice/purchase_einvoice.json | 23 + 11 files changed, 629 insertions(+) create mode 100644 erpnext/patches/v12_0/set_permission_einvoicing.py create mode 100644 erpnext/regional/doctype/import_supplier_invoice/__init__.py create mode 100644 erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js create mode 100644 erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.json create mode 100644 erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py create mode 100644 erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py create mode 100644 erpnext/regional/print_format/purchase_einvoice/__init__.py create mode 100644 erpnext/regional/print_format/purchase_einvoice/purchase_einvoice.json diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 4e72d5ecd6b..de4c89c5ace 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -650,3 +650,4 @@ erpnext.patches.v12_0.update_price_or_product_discount erpnext.patches.v12_0.add_export_type_field_in_party_master erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22 erpnext.patches.v12_0.create_irs_1099_field_united_states +erpnext.patches.v12_0.set_permission_einvoicing diff --git a/erpnext/patches/v12_0/set_permission_einvoicing.py b/erpnext/patches/v12_0/set_permission_einvoicing.py new file mode 100644 index 00000000000..1095c8c43e7 --- /dev/null +++ b/erpnext/patches/v12_0/set_permission_einvoicing.py @@ -0,0 +1,15 @@ +import frappe +from erpnext.regional.italy.setup import make_custom_fields +from frappe.permissions import add_permission, update_permission_property + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'Italy'}) + + if not company: + return + + make_custom_fields() + + add_permission('Import Supplier Invoice', 'Accounts Manager', 0) + update_permission_property('Import Supplier Invoice', 'Accounts Manager', 0, 'write', 1) + update_permission_property('Import Supplier Invoice', 'Accounts Manager', 0, 'create', 1) \ No newline at end of file diff --git a/erpnext/regional/doctype/import_supplier_invoice/__init__.py b/erpnext/regional/doctype/import_supplier_invoice/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js new file mode 100644 index 00000000000..c2d6edfc773 --- /dev/null +++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js @@ -0,0 +1,46 @@ +// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +frappe.ui.form.on('Import Supplier Invoice', { + onload: function(frm) { + frappe.realtime.on("import_invoice_update", function (data) { + frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message); + if (data.count == data.total) { + window.setTimeout(title => frm.dashboard.hide_progress(title), 1500, data.title); + } + }); + }, + setup: function(frm) { + frm.set_query("tax_account", function(doc) { + return { + filters: { + account_type: 'Tax', + company: doc.company + } + }; + }); + + frm.set_query("default_buying_price_list", function(doc) { + return { + filters: { + currency: frappe.get_doc(":Company", doc.company).default_currency + } + }; + }); + }, + + refresh: function(frm) { + frm.trigger("toggle_read_only_fields"); + }, + + toggle_read_only_fields: function(frm) { + if (in_list(["File Import Completed", "Processing File Data"], frm.doc.status)) { + cur_frm.set_read_only(); + cur_frm.refresh_fields(); + frm.set_df_property("import_invoices", "hidden", 1); + } else { + frm.set_df_property("import_invoices", "hidden", 0); + } + } + +}); \ No newline at end of file diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.json b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.json new file mode 100644 index 00000000000..59e955c23f4 --- /dev/null +++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.json @@ -0,0 +1,105 @@ +{ + "actions": [], + "creation": "2019-10-15 12:33:21.845329", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "invoice_series", + "company", + "item_code", + "column_break_5", + "supplier_group", + "tax_account", + "default_buying_price_list", + "upload_xml_invoices_section", + "zip_file", + "import_invoices", + "status" + ], + "fields": [ + { + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Company", + "options": "Company", + "reqd": 1 + }, + { + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Code", + "options": "Item", + "reqd": 1 + }, + { + "fieldname": "supplier_group", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Supplier Group", + "options": "Supplier Group", + "reqd": 1 + }, + { + "fieldname": "tax_account", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Tax Account", + "options": "Account", + "reqd": 1 + }, + { + "fieldname": "column_break_5", + "fieldtype": "Column Break" + }, + { + "fieldname": "zip_file", + "fieldtype": "Attach", + "label": "Zip File" + }, + { + "description": "Click on Import Invoices button once the zip file has been attached to the document. Any errors related to processing will be shown in the Error Log.", + "fieldname": "import_invoices", + "fieldtype": "Button", + "label": "Import Invoices", + "options": "process_file_data" + }, + { + "fieldname": "status", + "fieldtype": "Data", + "label": "Status", + "read_only": 1 + }, + { + "fieldname": "invoice_series", + "fieldtype": "Select", + "label": "Invoice Series", + "options": "ACC-PINV-.YYYY.-", + "reqd": 1 + }, + { + "fieldname": "default_buying_price_list", + "fieldtype": "Link", + "label": "Default Buying Price List", + "options": "Price List", + "reqd": 1 + }, + { + "fieldname": "upload_xml_invoices_section", + "fieldtype": "Section Break", + "label": "Upload XML Invoices" + } + ], + "links": [], + "modified": "2019-12-10 16:37:26.793398", + "modified_by": "Administrator", + "module": "Regional", + "name": "Import Supplier Invoice", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py new file mode 100644 index 00000000000..72fe17fb379 --- /dev/null +++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py @@ -0,0 +1,402 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +from decimal import Decimal +import json +import re +import traceback +import zipfile +import frappe, erpnext +from frappe import _ +from frappe.model.document import Document +from frappe.custom.doctype.custom_field.custom_field import create_custom_field +from frappe.utils.data import format_datetime +from bs4 import BeautifulSoup as bs +from frappe.utils import cint, flt, today, nowdate, add_days, get_files_path, get_datetime_str +import dateutil +from frappe.utils.file_manager import save_file + +class ImportSupplierInvoice(Document): + def validate(self): + if not frappe.db.get_value("Stock Settings", fieldname="stock_uom"): + frappe.throw(_("Please set default UOM in Stock Settings")) + + def autoname(self): + if not self.name: + self.name = "Import Invoice on " + format_datetime(self.creation) + + def import_xml_data(self): + import_file = frappe.get_doc("File", {"file_url": self.zip_file}) + self.publish("File Import", _("Processing XML Files"), 1, 3) + + self.file_count = 0 + self.purchase_invoices_count = 0 + self.default_uom = frappe.db.get_value("Stock Settings", fieldname="stock_uom") + + with zipfile.ZipFile(get_full_path(self.zip_file)) as zf: + for file_name in zf.namelist(): + content = get_file_content(file_name, zf) + file_content = bs(content, "xml") + self.prepare_data_for_import(file_content, file_name, content) + + if self.purchase_invoices_count == self.file_count: + self.status = "File Import Completed" + self.publish("File Import", _("XML Files Processed"), 2, 3) + else: + self.status = "Partially Completed - Check Error Log" + self.publish("File Import", _("XML Files Processed"), 2, 3) + + self.save() + self.publish("File Import", _("XML Files Processed"), 3, 3) + + def prepare_data_for_import(self, file_content, file_name, encoded_content): + for line in file_content.find_all("DatiGeneraliDocumento"): + invoices_args = { + "company": self.company, + "naming_series": self.invoice_series, + "document_type": line.TipoDocumento.text, + "bill_date": get_datetime_str(line.Data.text), + "invoice_no": line.Numero.text, + "total_discount": 0, + "items": [], + "buying_price_list": self.default_buying_price_list + } + + if not invoices_args.get("invoice_no", ''): return + + supp_dict = get_supplier_details(file_content) + invoices_args["destination_code"] = get_destination_code_from_file(file_content) + self.prepare_items_for_invoice(file_content, invoices_args) + invoices_args["taxes"] = get_taxes_from_file(file_content, self.tax_account) + invoices_args["terms"] = get_payment_terms_from_file(file_content) + + supplier_name = create_supplier(self.supplier_group, supp_dict) + address = create_address(supplier_name, supp_dict) + pi_name = create_purchase_invoice(supplier_name, file_name, invoices_args, self.name) + + self.file_count += 1 + if pi_name: + self.purchase_invoices_count += 1 + file_save = save_file(file_name, encoded_content, "Purchase Invoice", + pi_name, folder=None, decode=False, is_private=0, df=None) + + def prepare_items_for_invoice(self, file_content, invoices_args): + qty = 1 + rate, tax_rate = [0 ,0] + uom = self.default_uom + + #read file for item information + for line in file_content.find_all("DettaglioLinee"): + if line.find("PrezzoUnitario") and line.find("PrezzoTotale"): + rate = flt(line.PrezzoUnitario.text) or 0 + line_total = flt(line.PrezzoTotale.text) or 0 + + if rate and flt(line_total) / rate != 1.0 and line.find("Quantita"): + qty = flt(line.Quantita.text) or 0 + if line.find("UnitaMisura"): + uom = create_uom(line.UnitaMisura.text) + + if (rate < 0 and line_total < 0): + qty *= -1 + invoices_args["return_invoice"] = 1 + + if line.find("AliquotaIVA"): + tax_rate = flt(line.AliquotaIVA.text) + + line_str = re.sub('[^A-Za-z0-9]+', '-', line.Descrizione.text) + item_name = line_str[0:140] + + invoices_args['items'].append({ + "item_code": self.item_code, + "item_name": item_name, + "description": line_str, + "qty": qty, + "uom": uom, + "rate": abs(rate), + "conversion_factor": 1.0, + "tax_rate": tax_rate + }) + + for disc_line in line.find_all("ScontoMaggiorazione"): + if disc_line.find("Percentuale"): + invoices_args["total_discount"] += flt((flt(disc_line.Percentuale.text) / 100) * (rate * qty)) + + def process_file_data(self): + self.status = "Processing File Data" + self.save() + frappe.enqueue_doc(self.doctype, self.name, "import_xml_data", queue="long", timeout=3600) + + def publish(self, title, message, count, total): + frappe.publish_realtime("import_invoice_update", {"title": title, "message": message, "count": count, "total": total}) + +def get_file_content(file_name, zip_file_object): + content = '' + encoded_content = zip_file_object.read(file_name) + + try: + content = encoded_content.decode("utf-8-sig") + except UnicodeDecodeError: + try: + content = encoded_content.decode("utf-16") + except UnicodeDecodeError as e: + frappe.log_error(message=e, title="UTF-16 encoding error for File Name: " + file_name) + + return content + +def get_supplier_details(file_content): + supplier_info = {} + for line in file_content.find_all("CedentePrestatore"): + supplier_info['tax_id'] = line.DatiAnagrafici.IdPaese.text + line.DatiAnagrafici.IdCodice.text + if line.find("CodiceFiscale"): + supplier_info['fiscal_code'] = line.DatiAnagrafici.CodiceFiscale.text + + if line.find("RegimeFiscale"): + supplier_info['fiscal_regime'] = line.DatiAnagrafici.RegimeFiscale.text + + if line.find("Denominazione"): + supplier_info['supplier'] = line.DatiAnagrafici.Anagrafica.Denominazione.text + + if line.find("Nome"): + supplier_info['supplier'] = (line.DatiAnagrafici.Anagrafica.Nome.text + + " " + line.DatiAnagrafici.Anagrafica.Cognome.text) + + supplier_info['address_line1'] = line.Sede.Indirizzo.text + supplier_info['city'] = line.Sede.Comune.text + if line.find("Provincia"): + supplier_info['province'] = line.Sede.Provincia.text + + supplier_info['pin_code'] = line.Sede.CAP.text + supplier_info['country'] = get_country(line.Sede.Nazione.text) + + return supplier_info + +def get_taxes_from_file(file_content, tax_account): + taxes = [] + #read file for taxes information + for line in file_content.find_all("DatiRiepilogo"): + if line.find("AliquotaIVA"): + if line.find("EsigibilitaIVA"): + descr = line.EsigibilitaIVA.text + else: + descr = "None" + taxes.append({ + "charge_type": "Actual", + "account_head": tax_account, + "tax_rate": flt(line.AliquotaIVA.text) or 0, + "description": descr, + "tax_amount": flt(line.Imposta.text) if len(line.find("Imposta"))!=0 else 0 + }) + + return taxes + +def get_payment_terms_from_file(file_content): + terms = [] + #Get mode of payment dict from setup + mop_options = frappe.get_meta('Mode of Payment').fields[4].options + mop_str = re.sub('\n', ',', mop_options) + mop_dict = dict(item.split("-") for item in mop_str.split(",")) + #read file for payment information + for line in file_content.find_all("DettaglioPagamento"): + mop_code = line.ModalitaPagamento.text + '-' + mop_dict.get(line.ModalitaPagamento.text) + if line.find("DataScadenzaPagamento"): + due_date = dateutil.parser.parse(line.DataScadenzaPagamento.text).strftime("%Y-%m-%d") + else: + due_date = today() + terms.append({ + "mode_of_payment_code": mop_code, + "bank_account_iban": line.IBAN.text if line.find("IBAN") else "", + "due_date": due_date, + "payment_amount": line.ImportoPagamento.text + }) + + return terms + +def get_destination_code_from_file(file_content): + destination_code = '' + for line in file_content.find_all("DatiTrasmissione"): + destination_code = line.CodiceDestinatario.text + + return destination_code + +def create_supplier(supplier_group, args): + args = frappe._dict(args) + + existing_supplier_name = frappe.db.get_value("Supplier", + filters={"tax_id": args.tax_id}, fieldname="name") + if existing_supplier_name: + pass + else: + existing_supplier_name = frappe.db.get_value("Supplier", + filters={"name": args.supplier}, fieldname="name") + + if existing_supplier_name: + filters = [ + ["Dynamic Link", "link_doctype", "=", "Supplier"], + ["Dynamic Link", "link_name", "=", args.existing_supplier_name], + ["Dynamic Link", "parenttype", "=", "Contact"] + ] + + if not frappe.get_list("Contact", filters): + new_contact = frappe.new_doc("Contact") + new_contact.first_name = args.supplier + new_contact.append('links', { + "link_doctype": "Supplier", + "link_name": existing_supplier_name + }) + new_contact.insert(ignore_mandatory=True) + + return existing_supplier_name + else: + + new_supplier = frappe.new_doc("Supplier") + new_supplier.supplier_name = args.supplier + new_supplier.supplier_group = supplier_group + new_supplier.tax_id = args.tax_id + new_supplier.fiscal_code = args.fiscal_code + new_supplier.fiscal_regime = args.fiscal_regime + new_supplier.save() + + new_contact = frappe.new_doc("Contact") + new_contact.first_name = args.supplier + new_contact.append('links', { + "link_doctype": "Supplier", + "link_name": new_supplier.name + }) + + new_contact.insert(ignore_mandatory=True) + + return new_supplier.name + +def create_address(supplier_name, args): + args = frappe._dict(args) + + filters = [ + ["Dynamic Link", "link_doctype", "=", "Supplier"], + ["Dynamic Link", "link_name", "=", supplier_name], + ["Dynamic Link", "parenttype", "=", "Address"] + ] + + existing_address = frappe.get_list("Address", filters) + + if args.address_line1: + new_address_doc = frappe.new_doc("Address") + new_address_doc.address_line1 = args.address_line1 + + if args.city: + new_address_doc.city = args.city + else: + new_address_doc.city = "Not Provided" + + for field in ["province", "pincode", "country"]: + if args.get(field): + new_address_doc.set(field, args.get(field)) + + for address in existing_address: + address_doc = frappe.get_doc("Address", address["name"]) + if (address_doc.address_line1 == new_address_doc.address_line1 and + address_doc.pincode == new_address_doc.pincode): + return address + + new_address_doc.append("links", { + "link_doctype": "Supplier", + "link_name": supplier_name + }) + new_address_doc.address_type = "Billing" + new_address_doc.insert(ignore_mandatory=True) + return new_address_doc.name + else: + return None + +def create_purchase_invoice(supplier_name, file_name, args, name): + args = frappe._dict(args) + pi = frappe.get_doc({ + "doctype": "Purchase Invoice", + "company": args.company, + "currency": erpnext.get_company_currency(args.company), + "naming_series": args.naming_series, + "supplier": supplier_name, + "is_return": args.is_return, + "posting_date": today(), + "bill_no": args.bill_no, + "buying_price_list": args.buying_price_list, + "bill_date": args.bill_date, + "destination_code": args.destination_code, + "document_type": args.document_type, + "disable_rounded_total": 1, + "items": args["items"], + "taxes": args["taxes"] + }) + + try: + pi.set_missing_values() + pi.insert(ignore_mandatory=True) + + #if discount exists in file, apply any discount on grand total + if args.total_discount > 0: + pi.apply_discount_on = "Grand Total" + pi.discount_amount = args.total_discount + pi.save() + #adjust payment amount to match with grand total calculated + calc_total = 0 + adj = 0 + for term in args.terms: + calc_total += flt(term["payment_amount"]) + if flt(calc_total - flt(pi.grand_total)) != 0: + adj = calc_total - flt(pi.grand_total) + pi.payment_schedule = [] + for term in args.terms: + pi.append('payment_schedule',{"mode_of_payment_code": term["mode_of_payment_code"], + "bank_account_iban": term["bank_account_iban"], + "due_date": term["due_date"], + "payment_amount": flt(term["payment_amount"]) - adj }) + adj = 0 + pi.imported_grand_total = calc_total + pi.save() + return pi.name + except Exception as e: + frappe.db.set_value("Import Supplier Invoice", name, "status", "Error") + frappe.log_error(message=e, + title="Create Purchase Invoice: " + args.get("bill_no") + "File Name: " + file_name) + return None + +def get_country(code): + existing_country_name = frappe.db.get_value("Country", + filters={"code": code}, fieldname="name") + if existing_country_name: + return existing_country_name + else: + frappe.throw(_("Country Code in File does not match with country code set up in the system")) + +def create_uom(uom): + existing_uom = frappe.db.get_value("UOM", + filters={"uom_name": uom}, fieldname="uom_name") + if existing_uom: + return existing_uom + else: + new_uom = frappe.new_doc("UOM") + new_uom.uom_name = uom + new_uom.save() + return new_uom.uom_name + +def get_full_path(file_name): + """Returns file path from given file name""" + file_path = file_name + + if "/" not in file_path: + file_path = "/files/" + file_path + + if file_path.startswith("/private/files/"): + file_path = get_files_path(*file_path.split("/private/files/", 1)[1].split("/"), is_private=1) + + elif file_path.startswith("/files/"): + file_path = get_files_path(*file_path.split("/files/", 1)[1].split("/")) + + elif file_path.startswith("http"): + pass + + elif not self.file_url: + frappe.throw(_("There is some problem with the file url: {0}").format(file_path)) + + return file_path \ No newline at end of file diff --git a/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py new file mode 100644 index 00000000000..d1caf77fc2c --- /dev/null +++ b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +# import frappe +import unittest + +class TestImportSupplierInvoice(unittest.TestCase): + pass diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py index 1526d6f62f0..2d0ad66b0a0 100644 --- a/erpnext/regional/italy/setup.py +++ b/erpnext/regional/italy/setup.py @@ -155,6 +155,31 @@ def make_custom_fields(update=True): fetch_from="country.code"), dict(fieldname='state_code', label='State Code', fieldtype='Data', insert_after='state', print_hide=1) + ], + 'Purchase Invoice': [ + dict(fieldname='document_type', label='Document Type', + fieldtype='Data', insert_after='company', print_hide=1, read_only=1 + ), + dict(fieldname='destination_code', label='Destination Code', + fieldtype='Data', insert_after='company', print_hide=1, read_only=1 + ), + dict(fieldname='imported_grand_total', label='Imported Grand Total', + fieldtype='Data', insert_after='update_auto_repeat_reference', print_hide=1, read_only=1 + ) + ], + 'Purchase Taxes and Charges': [ + dict(fieldname='tax_rate', label='Tax Rate', + fieldtype='Data', insert_after='parenttype', print_hide=1, read_only=0 + ) + ], + 'Supplier': [ + dict(fieldname='fiscal_code', label='Fiscal Code', + fieldtype='Data', insert_after='tax_id', print_hide=1, read_only=1 + ), + dict(fieldname='fiscal_regime', label='Fiscal Regime', + fieldtype='Select', insert_after='fiscal_code', print_hide=1, read_only=1, + options= "\nRF01\nRF02\nRF04\nRF05\nRF06\nRF07\nRF08\nRF09\nRF10\nRF11\nRF12\nRF13\nRF14\nRF15\nRF16\nRF17\nRF18\nRF19" + ) ] } diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index bc8d00d8b8b..2af72f8e276 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -13,6 +13,8 @@ from erpnext.regional.italy import state_codes def update_itemised_tax_data(doc): if not doc.taxes: return + if doc.doctype == "Purchase Invoice": return + itemised_tax = get_itemised_tax(doc.taxes) for row in doc.items: diff --git a/erpnext/regional/print_format/purchase_einvoice/__init__.py b/erpnext/regional/print_format/purchase_einvoice/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/regional/print_format/purchase_einvoice/purchase_einvoice.json b/erpnext/regional/print_format/purchase_einvoice/purchase_einvoice.json new file mode 100644 index 00000000000..88f31dd1308 --- /dev/null +++ b/erpnext/regional/print_format/purchase_einvoice/purchase_einvoice.json @@ -0,0 +1,23 @@ +{ + "align_labels_right": 0, + "creation": "2019-10-16 00:47:08.877767", + "custom_format": 0, + "disabled": 1, + "doc_type": "Purchase Invoice", + "docstatus": 0, + "doctype": "Print Format", + "font": "Default", + "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"
\\t\\t\\t\\t

Purchase Invoice
{{ doc.name }}\\t\\t\\t\\t

\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
\\nCedente/prestatore (fornitore)\\n\\nCessionario/committente (cliente)\\n
\\n

Identificstivo fiscale ai fini IVA: {{frappe.db.get_value(\\\"Supplier\\\", doc.supplier, \\\"tax_id\\\")}}

\\n

Codice fiscale: {{frappe.db.get_value(\\\"Supplier\\\", doc.supplier, \\\"fiscal_code\\\")}}

\\n

Denominazione: {{frappe.db.get_value(\\\"Supplier\\\", doc.supplier, \\\"supplier_name\\\")}}

\\n

Regime fiscale: {{frappe.db.get_value(\\\"Supplier\\\", doc.supplier, \\\"fiscal_regime\\\")}}

\\n

Indrizo: {{frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"address_line1\\\")}}

\\n

Commune: {{frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"city\\\")}} Provincia: {{frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"state_code\\\")}}

\\n

Cap: {{(frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"pincode\\\")) or \\\" \\\"}} Nazione: {{frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"country\\\")}}

\\n
\\n

Identificstivo fiscale ai fini IVA: {{frappe.db.get_value(\\\"Company\\\", doc.company, \\\"tax_id\\\")}}

\\n

Codice fiscale: {{frappe.db.get_value(\\\"Company\\\", doc.company, \\\"fiscal_code\\\")}}

\\n

Denominazione: {{doc.company}}

\\n

Indrizo: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"address_line1\\\")}}

\\n

Commune: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"city\\\")}} Provincia: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"state_code\\\")}}

\\n

Cap: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"pincode\\\")}} Nazione: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"country\\\")}}

\\n
\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
\\nTipologla\\n\\nArt. 73\\n\\nNumero documento\\n\\nData documento\\n\\nCodice destinatario\\n
\\n{{doc.document_type or \\\" \\\"}}\\n\\n{{\\\" \\\"}}\\n\\n{{doc.bill_no or \\\" \\\"}}\\n\\n{{doc.get_formatted(\\\"bill_date\\\") or \\\" \\\"}}\\n\\n{{doc.destination_code or \\\" \\\"}}\\n
\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n{%- for row in doc.items -%}\\n\\n\\n\\n\\n\\n\\n\\n{%- endfor -%}\\n\\n
\\nDescrizione\\n\\nQuantita\\n\\nPrezzo unitario\\n\\nUM\\n\\n%IVA\\n\\nPrezzo totale\\n
\\n{{row.description or \\\" \\\"}}\\n\\n{{row.get_formatted(\\\"qty\\\", doc)}}\\n\\n{{row.get_formatted(\\\"rate\\\", doc)}}\\n\\n{{row.get_formatted(\\\"uom\\\", doc)}}\\n\\n{{row.get_formatted(\\\"tax_rate\\\", doc)}}\\n\\n{{row.get_formatted(\\\"amount\\\", doc)}}\\n
\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n{%- for row in doc.taxes -%}\\n\\n\\n\\n\\n\\n\\n\\n{%- endfor -%}\\n\\n
\\nesigibilita immediata / riferimenti normativi\\n\\n%IVA\\n\\nSpese accessorie\\n\\nArr.\\n\\nTotale imponibile\\n\\nTotale Imposta\\n
\\n{% if 'None' in row.description %}\\n {{ \\\" \\\" }}\\n{% else %}\\n{{row.description}}\\n{% endif %}\\n\\n{{row.get_formatted(\\\"tax_rate\\\", doc)}}\\n\\n{{\\\"0,00\\\"}}\\n\\n{{\\\" \\\"}}\\n\\n{{doc.get_formatted(\\\"base_net_total\\\")}}\\n\\n{{row.get_formatted(\\\"tax_amount\\\", doc)}}\\n
\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
\\nImporto bolio\\n\\nSconto/Magglorazione\\n\\nArr.\\n\\nTotale documento\\n
\\n{{\\\" \\\"}}\\n\\n{{\\\" \\\"}}\\n\\n{{\\\" \\\"}}\\n\\n{{doc.get_formatted(\\\"base_grand_total\\\")}}\\n
\\n
\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n{%- for row in doc.payment_schedule -%}\\n\\n\\n\\n\\n\\n\\n{%- endfor -%}\\n\\n
\\nModalita pagamento\\n\\nIBAN\\n\\nInstituto\\n\\nData scadenza\\n\\nImporto\\n
\\n{{row.get_formatted(\\\"mode_of_payment_code\\\",doc)}}\\n\\n{{row.get_formatted(\\\"bank_account_iban\\\",doc)}}\\n\\n{{\\\" \\\"}}\\n\\n{{row.get_formatted(\\\"due_date\\\",doc)}}\\n\\n{{row.get_formatted(\\\"payment_amount\\\",doc)}}\\n
\"}]", + "idx": 0, + "line_breaks": 0, + "modified": "2019-10-16 23:32:37.709344", + "modified_by": "Administrator", + "module": "Regional", + "name": "Purchase eInvoice", + "owner": "Administrator", + "print_format_builder": 1, + "print_format_type": "Jinja", + "raw_printing": 0, + "show_section_headings": 0, + "standard": "Yes" +} \ No newline at end of file From 243283eec875fa7c4f57caa2615c0c466d1cf312 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 24 Mar 2020 11:34:44 +0530 Subject: [PATCH 108/137] fix: batch selection popup not coming for stock entry --- erpnext/public/js/utils/serial_no_batch_selector.js | 6 +++++- erpnext/stock/doctype/stock_entry/stock_entry.js | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js index 23895ee4c02..101ac9cd610 100644 --- a/erpnext/public/js/utils/serial_no_batch_selector.js +++ b/erpnext/public/js/utils/serial_no_batch_selector.js @@ -313,11 +313,15 @@ erpnext.SerialNoBatchSelector = Class.extend({ frappe.throw(__(`Batch ${val} already selected.`)); return; } + + let batch_number = me.item.batch_no || + this.grid_row.on_grid_fields_dict.batch_no.get_value(); + if (me.warehouse_details.name) { frappe.call({ method: 'erpnext.stock.doctype.batch.batch.get_batch_qty', args: { - batch_no: me.item.batch_no, + batch_no: batch_number, warehouse: me.warehouse_details.name, item_code: me.item_code }, diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 92cc8f65047..23ee9f472b8 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -60,7 +60,8 @@ frappe.ui.form.on('Stock Entry', { } } - if(item.s_warehouse) filters["warehouse"] = item.s_warehouse; + filters["warehouse"] = item.s_warehouse || item.t_warehouse; + return { query : "erpnext.controllers.queries.get_batch_no", filters: filters @@ -886,7 +887,7 @@ erpnext.stock.select_batch_and_serial_no = (frm, item) => { } } - if(item && !item.has_serial_no && item.has_batch_no) return; + if(item && !item.has_serial_no && !item.has_batch_no) return; if (frm.doc.purpose === 'Material Receipt') return; frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() { From 87b3dbb2146da8061b8babea76036eb5e4566f30 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 2 Dec 2019 09:37:09 +0530 Subject: [PATCH 109/137] fix: Manufacturing UX, added calendar view for job card --- erpnext/manufacturing/doctype/bom/bom.js | 5 - .../doctype/bom/bom_dashboard.py | 4 +- .../doctype/job_card/job_card.js | 141 +- .../doctype/job_card/job_card.json | 1234 +++---------- .../doctype/job_card/job_card.py | 55 +- .../doctype/job_card/job_card_calendar.js | 21 + .../job_card_time_log/job_card_time_log.json | 247 +-- .../production_plan/production_plan.js | 3 +- .../production_plan/production_plan.json | 1618 +++-------------- .../production_plan_dashboard.py | 2 +- .../doctype/work_order/work_order.js | 178 +- .../doctype/work_order/work_order.json | 4 +- .../doctype/work_order/work_order.py | 38 +- .../doctype/work_order/work_order_calendar.js | 2 + .../work_order/work_order_dashboard.py | 3 +- .../work_order_operation.json | 9 +- 16 files changed, 918 insertions(+), 2646 deletions(-) create mode 100644 erpnext/manufacturing/doctype/job_card/job_card_calendar.js diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 8283fd7e6fc..3acaee4ffbd 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -6,7 +6,6 @@ frappe.provide("erpnext.bom"); frappe.ui.form.on("BOM", { setup: function(frm) { frm.custom_make_buttons = { - 'BOM': 'Duplicate BOM', 'Work Order': 'Work Order', 'Quality Inspection': 'Quality Inspection' }; @@ -91,10 +90,6 @@ frappe.ui.form.on("BOM", { } if(frm.doc.docstatus!=0) { - frm.add_custom_button(__("Duplicate BOM"), function() { - frm.copy_doc(); - }, __("Create")); - frm.add_custom_button(__("Work Order"), function() { frm.trigger("make_work_order"); }, __("Create")); diff --git a/erpnext/manufacturing/doctype/bom/bom_dashboard.py b/erpnext/manufacturing/doctype/bom/bom_dashboard.py index 060cd53ef19..1571125bb06 100644 --- a/erpnext/manufacturing/doctype/bom/bom_dashboard.py +++ b/erpnext/manufacturing/doctype/bom/bom_dashboard.py @@ -23,7 +23,5 @@ def get_data(): 'label': _('Subcontract'), 'items': ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'] } - ], - 'disable_create_buttons': ["Item", "Purchase Order", "Purchase Receipt", - "Purchase Invoice", "Job Card", "Stock Entry"] + ] } diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 1d9544d34f4..6db8f2f5b38 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -7,6 +7,8 @@ frappe.ui.form.on('Job Card', { if(frm.doc.docstatus == 0) { frm.set_df_property("operation", "read_only", frm.doc.operation_id ? 1 : 0); } + frappe.flags.pause_job = 0; + frappe.flags.resume_job = 0; if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) { if (frm.doc.for_quantity != frm.doc.transferred_qty) { @@ -18,44 +20,99 @@ frappe.ui.form.on('Job Card', { if (frm.doc.for_quantity != frm.doc.transferred_qty) { frm.add_custom_button(__("Material Transfer"), () => { frm.trigger("make_stock_entry"); - }); + }).addClass("btn-primary"); } } - if (frm.doc.docstatus == 0) { - frm.trigger("make_dashboard"); + if (frm.doc.docstatus == 0 && frm.doc.for_quantity > frm.doc.total_completed_qty + && (!frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) { + frm.trigger("prepare_timer_buttons"); + } + }, - if (!frm.doc.job_started) { - frm.add_custom_button(__("Start Job"), () => { - let row = frappe.model.add_child(frm.doc, 'Job Card Time Log', 'time_logs'); - row.from_time = frappe.datetime.now_datetime(); - frm.set_value('job_started', 1); - frm.set_value('started_time' , row.from_time); - frm.save(); - }); - } else { - frm.add_custom_button(__("Complete Job"), () => { - let completed_time = frappe.datetime.now_datetime(); - frm.doc.time_logs.forEach(d => { - if (d.from_time && !d.to_time) { - d.to_time = completed_time; - frm.set_value('started_time' , ''); - frm.set_value('job_started', 0); - frm.save(); + prepare_timer_buttons: function(frm) { + frm.trigger("make_dashboard"); + if (!frm.doc.job_started) { + frm.add_custom_button(__("Start"), () => { + if (!frm.doc.employee) { + frappe.prompt({fieldtype: 'Link', label: __('Employee'), options: "Employee", + fieldname: 'employee'}, d => { + if (d.employee) { + frm.set_value("employee", d.employee); } - }) - }); - } + + frm.events.start_job(frm); + }, __("Enter Value"), __("Start")); + } else { + frm.events.start_job(frm); + } + }).addClass("btn-primary"); + } else if (frm.doc.status == "On Hold") { + frm.add_custom_button(__("Resume"), () => { + frappe.flags.resume_job = 1; + frm.events.start_job(frm); + }).addClass("btn-primary"); + } else { + frm.add_custom_button(__("Pause"), () => { + frappe.flags.pause_job = 1; + frm.set_value("status", "On Hold"); + frm.events.complete_job(frm); + }); + + frm.add_custom_button(__("Complete"), () => { + let completed_time = frappe.datetime.now_datetime(); + frm.trigger("hide_timer"); + + frappe.prompt({fieldtype: 'Float', label: __('Completed Quantity'), + fieldname: 'qty', reqd: 1, default: frm.doc.for_quantity}, data => { + frm.events.complete_job(frm, completed_time, data.qty); + }, __("Enter Value"), __("Complete")); + }).addClass("btn-primary"); } }, + start_job: function(frm) { + let row = frappe.model.add_child(frm.doc, 'Job Card Time Log', 'time_logs'); + row.from_time = frappe.datetime.now_datetime(); + frm.set_value('job_started', 1); + frm.set_value('started_time' , row.from_time); + frm.set_value("status", "Work In Progress"); + + if (!frappe.flags.resume_job) { + frm.set_value('current_time' , 0); + } + + frm.save(); + }, + + complete_job: function(frm, completed_time, completed_qty) { + frm.doc.time_logs.forEach(d => { + if (d.from_time && !d.to_time) { + d.to_time = completed_time || frappe.datetime.now_datetime(); + d.completed_qty = completed_qty || 0; + + if(frappe.flags.pause_job) { + let currentIncrement = moment(d.to_time).diff(moment(d.from_time),"seconds") || 0; + frm.set_value('current_time' , currentIncrement + (frm.doc.current_time || 0)); + } else { + frm.set_value('started_time' , ''); + frm.set_value('job_started', 0); + frm.set_value('current_time' , 0); + } + + frm.save(); + } + }); + }, + make_dashboard: function(frm) { if(frm.doc.__islocal) return; frm.dashboard.refresh(); const timer = ` -
+
00 : 00 @@ -63,11 +120,16 @@ frappe.ui.form.on('Job Card', { 00
`; - var section = frm.dashboard.add_section(timer); + var section = frm.toolbar.page.add_inner_message(timer); - if (frm.doc.started_time) { - let currentIncrement = moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.started_time),"seconds"); - initialiseTimer(); + let currentIncrement = frm.doc.current_time || 0; + if (frm.doc.started_time || frm.doc.current_time) { + if (frm.doc.status == "On Hold") { + updateStopwatch(currentIncrement); + } else { + currentIncrement += moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.started_time),"seconds"); + initialiseTimer(); + } function initialiseTimer() { const interval = setInterval(function() { @@ -93,6 +155,10 @@ frappe.ui.form.on('Job Card', { } }, + hide_timer: function(frm) { + frm.toolbar.page.inner_toolbar.find(".stopwatch").remove(); + }, + for_quantity: function(frm) { frm.doc.items = []; frm.call({ @@ -122,5 +188,22 @@ frappe.ui.form.on('Job Card', { timer: function(frm) { return `` + }, + + set_total_completed_qty: function(frm) { + frm.doc.total_completed_qty = 0; + frm.doc.time_logs.forEach(d => { + if (d.completed_qty) { + frm.doc.total_completed_qty += d.completed_qty; + } + }); + + refresh_field("total_completed_qty"); } -}); \ No newline at end of file +}); + +frappe.ui.form.on('Job Card Time Log', { + completed_qty: function(frm) { + frm.events.set_total_completed_qty(frm); + } +}) \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json index 39c5cce313b..fd39af1faad 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.json +++ b/erpnext/manufacturing/doctype/job_card/job_card.json @@ -1,1004 +1,300 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "PO-JOB.#####", - "beta": 0, - "creation": "2018-07-09 17:23:29.518745", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "autoname": "naming_series:", + "creation": "2018-07-09 17:23:29.518745", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "naming_series", + "work_order", + "bom_no", + "workstation", + "operation", + "column_break_4", + "posting_date", + "company", + "remarks", + "production_section", + "production_item", + "item_name", + "for_quantity", + "wip_warehouse", + "column_break_12", + "employee", + "employee_name", + "status", + "project", + "timing_detail", + "time_logs", + "section_break_13", + "total_completed_qty", + "total_time_in_mins", + "column_break_15", + "section_break_8", + "items", + "more_information", + "operation_id", + "transferred_qty", + "requested_qty", + "column_break_20", + "barcode", + "job_started", + "started_time", + "current_time", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "work_order", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Work Order", - "length": 0, - "no_copy": 0, - "options": "Work Order", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "work_order", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Work Order", + "options": "Work Order", + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "bom_no", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "BOM No", - "length": 0, - "no_copy": 0, - "options": "BOM", - "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 - }, + "fetch_from": "work_order.bom_no", + "fieldname": "bom_no", + "fieldtype": "Link", + "label": "BOM No", + "options": "BOM", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "workstation", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Workstation", - "length": 0, - "no_copy": 0, - "options": "Workstation", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "workstation", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Workstation", + "options": "Workstation", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "operation", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Operation", - "length": 0, - "no_copy": 0, - "options": "Operation", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "operation", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Operation", + "options": "Operation", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break_4", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fetch_if_empty": 0, - "fieldname": "posting_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Posting Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Today", + "fieldname": "posting_date", + "fieldtype": "Date", + "label": "Posting Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "for_quantity", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "For Quantity", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "for_quantity", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Qty To Manufacture", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "wip_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "WIP Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "wip_warehouse", + "fieldtype": "Link", + "label": "WIP Warehouse", + "options": "Warehouse", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "timing_detail", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Timing Detail", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "timing_detail", + "fieldtype": "Section Break", + "label": "Timing Detail" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "employee", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Employee", - "length": 0, - "no_copy": 0, - "options": "Employee", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "employee", + "fieldtype": "Link", + "in_standard_filter": 1, + "label": "Employee", + "options": "Employee" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "time_logs", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Time Logs", - "length": 0, - "no_copy": 0, - "options": "Job Card Time Log", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "time_logs", + "fieldtype": "Table", + "label": "Time Logs", + "options": "Job Card Time Log" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "section_break_13", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_13", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "total_completed_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Total Completed Qty", - "length": 0, - "no_copy": 0, - "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 - }, + "fieldname": "total_completed_qty", + "fieldtype": "Float", + "label": "Total Completed Qty", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break_15", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_15", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "total_time_in_mins", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Total Time in Mins", - "length": 0, - "no_copy": 0, - "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 - }, + "fieldname": "total_time_in_mins", + "fieldtype": "Float", + "label": "Total Time in Mins", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "section_break_8", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Raw Materials", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_8", + "fieldtype": "Section Break", + "label": "Raw Materials" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Items", - "length": 0, - "no_copy": 0, - "options": "Job Card Item", - "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 - }, + "fieldname": "items", + "fieldtype": "Table", + "label": "Items", + "options": "Job Card Item", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "more_information", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "More Information", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "more_information", + "fieldtype": "Section Break", + "label": "More Information" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "operation_id", - "fieldtype": "Data", - "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": "Operation ID", - "length": 0, - "no_copy": 0, - "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 - }, + "fieldname": "operation_id", + "fieldtype": "Data", + "hidden": 1, + "label": "Operation ID", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fetch_if_empty": 0, - "fieldname": "transferred_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Transferred Qty", - "length": 0, - "no_copy": 0, - "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 - }, + "default": "0", + "fieldname": "transferred_qty", + "fieldtype": "Float", + "label": "Transferred Qty", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fetch_if_empty": 0, - "fieldname": "requested_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Requested Qty", - "length": 0, - "no_copy": 0, - "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 - }, + "default": "0", + "fieldname": "requested_qty", + "fieldtype": "Float", + "label": "Requested Qty", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "project", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Project", - "length": 0, - "no_copy": 0, - "options": "Project", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "remarks", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Remarks", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "remarks", + "fieldtype": "Small Text", + "label": "Remarks" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break_20", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_20", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Open", - "fetch_if_empty": 0, - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 1, - "options": "Open\nWork In Progress\nMaterial Transferred\nSubmitted\nCancelled\nCompleted", - "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 - }, + "default": "Open", + "fieldname": "status", + "fieldtype": "Select", + "label": "Status", + "no_copy": 1, + "options": "Open\nWork In Progress\nMaterial Transferred\nOn Hold\nSubmitted\nCancelled\nCompleted", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "job_started", - "fieldtype": "Check", - "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": "Job Started", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "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 - }, + "default": "0", + "fieldname": "job_started", + "fieldtype": "Check", + "hidden": 1, + "label": "Job Started", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "started_time", - "fieldtype": "Datetime", - "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": "Started Time", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "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 - }, + "fieldname": "started_time", + "fieldtype": "Datetime", + "hidden": 1, + "label": "Started Time", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amended From", - "length": 0, - "no_copy": 1, - "options": "Job Card", - "permlevel": 0, - "print_hide": 1, - "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 + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Job Card", + "print_hide": 1, + "read_only": 1 + }, + { + "default": "PO-JOB.#####", + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Naming Series", + "options": "PO-JOB.#####", + "reqd": 1 + }, + { + "fetch_from": "employee.employee_name", + "fieldname": "employee_name", + "fieldtype": "Read Only", + "label": "Employee Name" + }, + { + "fieldname": "production_section", + "fieldtype": "Section Break", + "label": "Production" + }, + { + "fieldname": "column_break_12", + "fieldtype": "Column Break" + }, + { + "fetch_from": "work_order.production_item", + "fieldname": "production_item", + "fieldtype": "Read Only", + "label": "Production Item" + }, + { + "fieldname": "barcode", + "fieldtype": "Barcode", + "label": "Barcode", + "read_only": 1 + }, + { + "fetch_from": "work_order.item_name", + "fieldname": "item_name", + "fieldtype": "Read Only", + "label": "Item Name" + }, + { + "fieldname": "current_time", + "fieldtype": "Int", + "hidden": 1, + "label": "Current Time", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-03-10 17:38:37.499871", - "modified_by": "Administrator", - "module": "Manufacturing", - "name": "Job Card", - "name_case": "", - "owner": "Administrator", + ], + "is_submittable": 1, + "modified": "2020-03-24 13:08:57.926201", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Job Card", + "owner": "Administrator", "permissions": [ { "amend": 1, diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index 9d2e620e584..eec7d242871 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import flt, time_diff_in_hours, get_datetime +from frappe.utils import flt, time_diff_in_hours, get_datetime, time_diff from frappe.model.mapper import get_mapped_doc from frappe.model.document import Document @@ -95,8 +95,9 @@ class JobCard(Document): if self.total_completed_qty <= 0.0: frappe.throw(_("Total completed qty must be greater than zero")) - if self.total_completed_qty > self.for_quantity: - frappe.throw(_("Total completed qty can not be greater than for quantity")) + if self.total_completed_qty != self.for_quantity: + frappe.throw(_("The total completed qty({0}) must be equal to qty to manufacture({1})" + .format(frappe.bold(self.total_completed_qty),frappe.bold(self.for_quantity)))) def update_work_order(self): if not self.work_order: @@ -172,6 +173,8 @@ class JobCard(Document): self.set_status(update_status) def set_status(self, update_status=False): + if self.status == "On Hold": return + self.status = { 0: "Open", 1: "Submitted", @@ -230,6 +233,7 @@ def make_stock_entry(source_name, target_doc=None): target.fg_completed_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0) target.calculate_rate_and_amount() target.set_missing_values() + target.set_stock_entry_type() doclist = get_mapped_doc("Job Card", source_name, { "Job Card": { @@ -251,3 +255,48 @@ def make_stock_entry(source_name, target_doc=None): }, target_doc, set_missing_values) return doclist + +def time_diff_in_minutes(string_ed_date, string_st_date): + return time_diff(string_ed_date, string_st_date).total_seconds() / 60 + +@frappe.whitelist() +def get_job_details(start, end, filters=None): + events = [] + + event_color = { + "Completed": "#cdf5a6", + "Material Transferred": "#ffdd9e", + "Work In Progress": "#D3D3D3" + } + + from frappe.desk.reportview import get_filters_cond + conditions = get_filters_cond("Job Card", filters, []) + + job_cards = frappe.db.sql(""" SELECT `tabJob Card`.name, `tabJob Card`.work_order, + `tabJob Card`.employee_name, `tabJob Card`.status, ifnull(`tabJob Card`.remarks, ''), + min(`tabJob Card Time Log`.from_time) as from_time, + max(`tabJob Card Time Log`.to_time) as to_time + FROM `tabJob Card` , `tabJob Card Time Log` + WHERE + `tabJob Card`.name = `tabJob Card Time Log`.parent {0} + group by `tabJob Card`.name""".format(conditions), as_dict=1) + + for d in job_cards: + subject_data = [] + for field in ["name", "work_order", "remarks", "employee_name"]: + if not d.get(field): continue + + subject_data.append(d.get(field)) + + color = event_color.get(d.status) + job_card_data = { + 'from_time': d.from_time, + 'to_time': d.to_time, + 'name': d.name, + 'subject': '\n'.join(subject_data), + 'color': color if color else "#89bcde" + } + + events.append(job_card_data) + + return events diff --git a/erpnext/manufacturing/doctype/job_card/job_card_calendar.js b/erpnext/manufacturing/doctype/job_card/job_card_calendar.js new file mode 100644 index 00000000000..cf07698ad6a --- /dev/null +++ b/erpnext/manufacturing/doctype/job_card/job_card_calendar.js @@ -0,0 +1,21 @@ +frappe.views.calendar["Job Card"] = { + field_map: { + "start": "from_time", + "end": "to_time", + "id": "name", + "title": "subject", + "color": "color", + "allDay": "allDay", + "progress": "progress" + }, + gantt: true, + filters: [ + { + "fieldtype": "Link", + "fieldname": "employee", + "options": "Employee", + "label": __("Employee") + } + ], + get_events_method: "erpnext.manufacturing.doctype.job_card.job_card.get_job_details" +}; diff --git a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json index 2aab71dee4f..9dd54dd6182 100644 --- a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json +++ b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json @@ -1,208 +1,57 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2019-03-08 23:56:43.187569", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "creation": "2019-03-08 23:56:43.187569", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "from_time", + "to_time", + "column_break_2", + "time_in_mins", + "completed_qty" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "from_time", - "fieldtype": "Datetime", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "From Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "from_time", + "fieldtype": "Datetime", + "in_list_view": 1, + "label": "From Time" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "to_time", - "fieldtype": "Datetime", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "To Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "to_time", + "fieldtype": "Datetime", + "in_list_view": 1, + "label": "To Time" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break_2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_2", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "time_in_mins", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Time In Mins", - "length": 0, - "no_copy": 0, - "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 - }, + "fieldname": "time_in_mins", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Time In Mins", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fetch_if_empty": 0, - "fieldname": "completed_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Completed Qty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "fieldname": "completed_qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Completed Qty", + "reqd": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2019-03-10 17:08:46.504910", - "modified_by": "Administrator", - "module": "Manufacturing", - "name": "Job Card Time Log", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "ASC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "istable": 1, + "modified": "2019-12-03 12:56:02.285448", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Job Card Time Log", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "ASC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 3b24d0fa0ff..2b168d1d76d 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -71,12 +71,13 @@ frappe.ui.form.on('Production Plan', { }, __('Create')); } + frm.page.set_inner_btn_group_as_primary(__('Create')); frm.trigger("material_requirement"); const projected_qty_formula = ` + {%= format_currency(data[i]["invoiced"], data[0]["currency"] ) %} {% if(!filters.show_future_payments) { %} - + {%= format_currency(data[i]["paid"], data[0]["currency"]) %} + {% } %} + {%= format_currency(data[i]["outstanding"], data[0]["currency"]) %} {% if(filters.show_future_payments) { %} {% if(report.report_name === "Accounts Receivable") { %} @@ -234,8 +234,8 @@ {%= data[i]["po_no"] %} {% } %} - - + + {% } %} {% } %} {% } else { %} @@ -256,10 +256,10 @@ {% } else { %} {% } %} - - - - + + + + {% } %} {% } %} From 728edacfd4231e9878b8b9d17ef55a20b7d6b3a6 Mon Sep 17 00:00:00 2001 From: Anupam K Date: Sat, 28 Mar 2020 13:48:42 +0530 Subject: [PATCH 125/137] bug: Item-wise Sales History - Billed amount --- .../report/item_wise_sales_history/item_wise_sales_history.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py index 1fc3663bed7..405004ece54 100644 --- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py +++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py @@ -121,8 +121,8 @@ def get_columns(filters): }, { "label": _("Billed Amount"), - "fieldname": "rate", - "options": "billed_amount", + "fieldtype": "currency", + "fieldname": "billed_amount", "width": 120 }, { From f9ce7c2e18872cf2248ea1b0c156133cf712ff64 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sat, 28 Mar 2020 19:12:59 +0530 Subject: [PATCH 126/137] chore: [ux] filter warehouse based on company --- erpnext/stock/report/stock_ledger/stock_ledger.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.js b/erpnext/stock/report/stock_ledger/stock_ledger.js index 3fab3273b9e..1813c2b5bd7 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.js +++ b/erpnext/stock/report/stock_ledger/stock_ledger.js @@ -29,7 +29,13 @@ frappe.query_reports["Stock Ledger"] = { "fieldname":"warehouse", "label": __("Warehouse"), "fieldtype": "Link", - "options": "Warehouse" + "options": "Warehouse", + "get_query": function() { + const company = frappe.query_report.get_filter_value('company'); + return { + filters: { 'company': company } + } + } }, { "fieldname":"item_code", From 1125ed883039cc2eb3fc09333c0bde28b199505e Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sat, 28 Mar 2020 16:39:22 +0530 Subject: [PATCH 127/137] fix: currency formatting in gl entry dr cr field --- erpnext/accounts/doctype/gl_entry/gl_entry.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json index e64bc9e0c78..2214811d8b3 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.json +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json @@ -114,13 +114,13 @@ "fieldname": "debit_in_account_currency", "fieldtype": "Currency", "label": "Debit Amount in Account Currency", - "options": "currency" + "options": "account_currency" }, { "fieldname": "credit_in_account_currency", "fieldtype": "Currency", "label": "Credit Amount in Account Currency", - "options": "currency" + "options": "account_currency" }, { "fieldname": "against", @@ -250,7 +250,7 @@ "icon": "fa fa-list", "idx": 1, "in_create": 1, - "modified": "2020-02-10 04:54:57.777905", + "modified": "2020-03-28 16:22:33.766994", "modified_by": "Administrator", "module": "Accounts", "name": "GL Entry", From 8ba661b8edb54454e4351cfc416bdac56976aea3 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sat, 28 Mar 2020 20:11:26 +0530 Subject: [PATCH 128/137] chore: hyperlinks in cannot cancel message --- erpnext/controllers/buying_controller.py | 2 +- erpnext/manufacturing/doctype/work_order/work_order.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index a47507eaf7b..61bd5032cee 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -731,7 +731,7 @@ class BuyingController(StockController): asset.supplier = None if asset.docstatus == 1 and delete_asset: frappe.throw(_('Cannot cancel this document as it is linked with submitted asset {0}.\ - Please cancel the it to continue.').format(asset.name)) + Please cancel the it to continue.').format(frappe.utils.get_link_to_form('Asset', asset.name))) asset.flags.ignore_validate_update_after_submit = True asset.flags.ignore_mandatory = True diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 83579414812..bd2ae6c36b1 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -274,7 +274,7 @@ class WorkOrder(Document): stock_entry = frappe.db.sql("""select name from `tabStock Entry` where work_order = %s and docstatus = 1""", self.name) if stock_entry: - frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(stock_entry[0][0])) + frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(frappe.utils.get_link_to_form('Stock Entry', stock_entry[0][0]))) def update_planned_qty(self): update_bin_qty(self.production_item, self.fg_warehouse, { From dc04cbf9a98282bc8ff6bd87cb358be126911832 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sun, 29 Mar 2020 12:52:16 +0530 Subject: [PATCH 129/137] fix: cannot view report for course doctype - permission problem --- erpnext/education/doctype/course/course.json | 26 +++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/erpnext/education/doctype/course/course.json b/erpnext/education/doctype/course/course.json index 68426c36be1..da10db1857a 100644 --- a/erpnext/education/doctype/course/course.json +++ b/erpnext/education/doctype/course/course.json @@ -74,7 +74,7 @@ } ], "image_field": "hero_image", - "modified": "2019-06-12 12:34:23.748157", + "modified": "2020-03-29 12:50:27.677589", "modified_by": "Administrator", "module": "Education", "name": "Course", @@ -103,6 +103,30 @@ "role": "Instructor", "share": 1, "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Administrator", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Education Manager", + "share": 1, + "write": 1 } ], "restrict_to_domain": "Education", From 7e7787c298508dbb741403b9dc5a26c8d743ea2d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sun, 29 Mar 2020 16:33:30 +0530 Subject: [PATCH 130/137] fix: not able to add equity account in the chart of accounts --- erpnext/accounts/doctype/account/account.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 1407d5f5fe3..0a72d4fa4e6 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -102,15 +102,15 @@ class Account(NestedSet): if not frappe.db.get_value("Account", {'account_name': self.account_name, 'company': ancestors[0]}, 'name'): frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0])) - else: + elif self.parent_account: descendants = get_descendants_of('Company', self.company) if not descendants: return parent_acc_name_map = {} parent_acc_name, parent_acc_number = frappe.db.get_value('Account', self.parent_account, \ ["account_name", "account_number"]) - filters = { + filters = { "company": ["in", descendants], - "account_name": parent_acc_name, + "account_name": parent_acc_name, } if parent_acc_number: filters["account_number"] = parent_acc_number From 83111a4a2a05c2b9a493bf8f834534703a426c81 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 31 Mar 2020 10:45:37 +0530 Subject: [PATCH 131/137] fix: Expense account currency validation in Landed Cost voucher (#21074) * fix: Expense account currency validation in Landed Cost voucher * fix: Remove unused imports --- erpnext/controllers/queries.py | 14 +++++++++----- .../landed_cost_voucher/landed_cost_voucher.py | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index d18f8e54d8f..163ef72ee10 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import frappe +import erpnext from frappe.desk.reportview import get_match_cond, get_filters_cond from frappe.utils import nowdate, getdate from collections import defaultdict @@ -129,23 +130,26 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters): }) def tax_account_query(doctype, txt, searchfield, start, page_len, filters): + company_currency = erpnext.get_company_currency(filters.get('company')) + tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount where tabAccount.docstatus!=2 and account_type in (%s) and is_group = 0 and company = %s + and account_currency = %s and `%s` LIKE %s order by idx desc, name limit %s, %s""" % - (", ".join(['%s']*len(filters.get("account_type"))), "%s", searchfield, "%s", "%s", "%s"), - tuple(filters.get("account_type") + [filters.get("company"), "%%%s%%" % txt, + (", ".join(['%s']*len(filters.get("account_type"))), "%s", "%s", searchfield, "%s", "%s", "%s"), + tuple(filters.get("account_type") + [filters.get("company"), company_currency, "%%%s%%" % txt, start, page_len])) if not tax_accounts: tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount where tabAccount.docstatus!=2 and is_group = 0 - and company = %s and `%s` LIKE %s limit %s, %s""" - % ("%s", searchfield, "%s", "%s", "%s"), - (filters.get("company"), "%%%s%%" % txt, start, page_len)) + and company = %s and account_currency = %s and `%s` LIKE %s limit %s, %s""" #nosec + % ("%s", "%s", searchfield, "%s", "%s", "%s"), + (filters.get("company"), company_currency, "%%%s%%" % txt, start, page_len)) return tax_accounts diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index d97b699a0f3..5ad0e13db9a 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -8,6 +8,7 @@ from frappe.utils import flt from frappe.model.meta import get_field_precision from frappe.model.document import Document from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos +from erpnext.accounts.doctype.account.account import get_account_currency class LandedCostVoucher(Document): def get_items_from_purchase_receipts(self): @@ -43,6 +44,7 @@ class LandedCostVoucher(Document): else: self.validate_applicable_charges_for_item() self.validate_purchase_receipts() + self.validate_expense_accounts() self.set_total_taxes_and_charges() def check_mandatory(self): @@ -71,6 +73,14 @@ class LandedCostVoucher(Document): frappe.throw(_("Row {0}: Cost center is required for an item {1}") .format(item.idx, item.item_code)) + def validate_expense_accounts(self): + company_currency = erpnext.get_company_currency(self.company) + for account in self.taxes: + if get_account_currency(account.expense_account) != company_currency: + frappe.throw(msg=_(""" Row {0}: Expense account currency should be same as company's default currency. + Please select expense account with account currency as {1}""") + .format(account.idx, frappe.bold(company_currency)), title=_("Invalid Account Currency")) + def set_total_taxes_and_charges(self): self.total_taxes_and_charges = sum([flt(d.amount) for d in self.get("taxes")]) From f492ba1e2dff0843d2d0383bfd55c4b1bd056790 Mon Sep 17 00:00:00 2001 From: Saqib Date: Tue, 31 Mar 2020 10:48:57 +0530 Subject: [PATCH 132/137] fix: auto created asset message (#21109) * fix: auto created asset message * Update erpnext/controllers/buying_controller.py Co-authored-by: Nabin Hait --- erpnext/controllers/buying_controller.py | 33 +++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 61bd5032cee..ff07b59bd9b 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -658,19 +658,32 @@ class BuyingController(StockController): # If asset has to be auto created # Check for asset naming series if item_data.get('asset_naming_series'): + created_assets = [] + for qty in range(cint(d.qty)): - self.make_asset(d) - is_plural = 's' if cint(d.qty) != 1 else '' - messages.append(_('{0} Asset{2} Created for {1}').format(cint(d.qty), d.item_code, is_plural)) + asset = self.make_asset(d) + created_assets.append(asset) + + if len(created_assets) > 5: + # dont show asset form links if more than 5 assets are created + messages.append(_('{} Asset{} created for {}').format(len(created_assets), is_plural, frappe.bold(d.item_code))) + else: + assets_link = list(map(lambda d: frappe.utils.get_link_to_form('Asset', d), created_assets)) + assets_link = frappe.bold(','.join(assets_link)) + + is_plural = 's' if len(created_assets) != 1 else '' + messages.append( + _('Asset{} {assets_link} created for {}').format(is_plural, frappe.bold(d.item_code), assets_link=assets_link) + ) else: - frappe.throw(_("Row {1}: Asset Naming Series is mandatory for the auto creation for item {0}") - .format(d.item_code, d.idx)) + frappe.throw(_("Row {}: Asset Naming Series is mandatory for the auto creation for item {}") + .format(d.idx, frappe.bold(d.item_code))) else: - messages.append(_("Assets not created for {0}. You will have to create asset manually.") - .format(d.item_code)) + messages.append(_("Assets not created for {0}. You will have to create asset manually.") + .format(frappe.bold(d.item_code))) for message in messages: - frappe.msgprint(message, title="Success") + frappe.msgprint(message, title="Success", indicator="green") def make_asset(self, row): if not row.asset_location: @@ -702,6 +715,8 @@ class BuyingController(StockController): asset.set_missing_values() asset.insert() + return asset.name + def update_fixed_asset(self, field, delete_asset = False): for d in self.get("items"): if d.is_fixed_asset: @@ -1012,4 +1027,4 @@ def get_batches_with_qty(item_code, fg_item, required_qty, transferred_batch_qty available_batches.append({'batch': batch, 'qty': available_qty}) required_qty -= available_qty - return available_batches \ No newline at end of file + return available_batches From d13e7d00b0b07e8c4be404dd2fbfe96ca769645c Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Tue, 31 Mar 2020 10:50:53 +0530 Subject: [PATCH 133/137] fix: email_to, party_type and party are not set in payment request (#21085) * fix: email_to, party_type and party are not set in payment request when order made from portal * fix: email_to, party_type and party are not set in payment request when order made from portal Co-authored-by: Anupam K --- erpnext/accounts/doctype/payment_request/payment_request.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 6b74f477f2b..34132e9a915 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -317,13 +317,13 @@ def make_payment_request(**args): "payment_request_type": args.get("payment_request_type"), "currency": ref_doc.currency, "grand_total": grand_total, - "email_to": args.recipient_id or "", + "email_to": args.recipient_id or ref_doc.owner, "subject": _("Payment Request for {0}").format(args.dn), "message": gateway_account.get("message") or get_dummy_message(ref_doc), "reference_doctype": args.dt, "reference_name": args.dn, - "party_type": args.get("party_type"), - "party": args.get("party"), + "party_type": args.get("party_type") or "Customer", + "party": args.get("party") or ref_doc.customer, "bank_account": bank_account }) From b80213d65dbc34e137ca48225d24094ce122a607 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 31 Mar 2020 10:52:51 +0530 Subject: [PATCH 134/137] fix: Healthcare Domain Issues (#21112) * fix (Lab Test): None TypeError in Patient Medical Record * fix: Lab Test Template data import failing in Lab Test Item creation * fix: disabled Procedure Template shown as enabled in List View * fix: change item_code from Link to Data to avoid item not found error * fix: disabled patient shown as enabled * fix: disabled practitioner schedule shown as enabled in list view * fix: appointment reminders not working * fix: Batch not getting fetched in Clinical Procedure Item --- .../clinical_procedure/clinical_procedure.js | 20 +- .../clinical_procedure_template.js | 33 +- .../clinical_procedure_template.json | 969 ++++------------- .../clinical_procedure_template.py | 100 +- .../healthcare_settings.json | 1 + .../healthcare/doctype/lab_test/lab_test.py | 14 +- .../lab_test_template/lab_test_template.py | 7 +- erpnext/healthcare/doctype/patient/patient.js | 2 +- .../healthcare/doctype/patient/patient.json | 26 +- erpnext/healthcare/doctype/patient/patient.py | 6 +- .../patient_appointment.js | 15 +- .../patient_appointment.json | 993 ++---------------- .../patient_appointment.py | 36 +- .../patient_encounter/patient_encounter.js | 2 +- .../practitioner_schedule.json | 209 ++-- erpnext/hooks.py | 4 +- 16 files changed, 451 insertions(+), 1986 deletions(-) diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js index fa9188449e3..cf8c9b9ca35 100644 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js +++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js @@ -5,20 +5,16 @@ frappe.ui.form.on('Clinical Procedure', { setup: function(frm) { frm.set_query('batch_no', 'items', function(doc, cdt, cdn) { var item = locals[cdt][cdn]; - if(!item.item_code) { - frappe.throw(__("Please enter Item Code to get Batch Number")); + if (!item.item_code) { + frappe.throw(__('Please enter Item Code to get Batch Number')); } else { + let filters = {'item_code': item.item_code}; + if (frm.doc.status == 'In Progress') { - var filters = { - 'item_code': item.item_code, - 'posting_date': frm.doc.start_date || frappe.datetime.nowdate() - }; - if(frm.doc.warehouse) filters["warehouse"] = frm.doc.warehouse; - } else { - filters = { - 'item_code': item.item_code - }; + filters['posting_date'] = frm.doc.start_date || frappe.datetime.nowdate(); + if (frm.doc.warehouse) filters['warehouse'] = frm.doc.warehouse; } + return { query : "erpnext.controllers.queries.get_batch_no", filters: filters @@ -29,7 +25,7 @@ frappe.ui.form.on('Clinical Procedure', { refresh: function(frm) { frm.set_query("patient", function () { return { - filters: {"disabled": 0} + filters: {"status": "Active"} }; }); frm.set_query("appointment", function () { diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js index 583728dd185..de0f9c43003 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js @@ -31,17 +31,7 @@ frappe.ui.form.on('Clinical Procedure Template', { if(!frm.doc.__islocal) { cur_frm.add_custom_button(__('Change Item Code'), function() { change_template_code(frm.doc); - } ); - if(frm.doc.disabled == 1){ - cur_frm.add_custom_button(__('Enable Template'), function() { - enable_template(frm.doc); - } ); - } - else{ - cur_frm.add_custom_button(__('Disable Template'), function() { - disable_template(frm.doc); - } ); - } + }); } } }); @@ -52,27 +42,6 @@ var mark_change_in_item = function(frm) { } }; -var disable_template = function(doc){ - frappe.call({ - method: "erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.disable_enable_template", - args: {status: 1, name: doc.name, item_code: doc.item_code, is_billable: doc.is_billable}, - callback: function(){ - cur_frm.reload_doc(); - } - }); -}; - -var enable_template = function(doc){ - frappe.call({ - method: "erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.disable_enable_template", - args: {status: 0, name: doc.name, item_code: doc.item_code, is_billable: doc.is_billable}, - callback: function(){ - cur_frm.reload_doc(); - } - }); -}; - - var change_template_code = function(doc){ var d = new frappe.ui.Dialog({ title:__("Change Template Code"), diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json index 26564a34ce4..7ae4be84a28 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json @@ -1,807 +1,230 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:template", - "beta": 1, - "creation": "2017-10-05 14:59:55.438359", - "custom": 0, - "description": "Procedure Template", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:template", + "beta": 1, + "creation": "2017-10-05 14:59:55.438359", + "description": "Procedure Template", + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "template", + "item", + "item_code", + "item_group", + "description", + "column_break_5", + "disabled", + "is_billable", + "rate", + "medical_department", + "consumables", + "consume_stock", + "items", + "sample_collection", + "sample", + "sample_uom", + "sample_qty", + "column_break_21", + "sample_details", + "change_in_item" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "template", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Template Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "fieldname": "template", + "fieldtype": "Data", + "in_global_search": 1, + "in_list_view": 1, + "label": "Template Name", + "reqd": 1, "unique": 1 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_code", + "fieldname": "item_code", + "fieldtype": "Data", + "label": "Item Code", + "options": "Item", + "reqd": 1 + }, + { + "fieldname": "item_group", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 1, - "options": "Item", - "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 - }, + "ignore_user_permissions": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Item Group", + "options": "Item Group", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Item Group", - "length": 0, - "no_copy": 0, - "options": "Item Group", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "medical_department", + "fieldtype": "Link", + "label": "Medical Department", + "options": "Medical Department" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "medical_department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Medical Department", - "length": 0, - "no_copy": 0, - "options": "Medical Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_5", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_5", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "is_billable", + "fieldtype": "Check", + "label": "Is Billable" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "is_billable", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Is Billable", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "is_billable", + "fieldname": "rate", + "fieldtype": "Float", + "label": "Rate", + "mandatory_depends_on": "is_billable" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_billable", - "fieldname": "rate", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "description", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Description", + "no_copy": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "consume_stock", + "fieldtype": "Check", + "label": "Allow Stock Consumption", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "section_break_9", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "consumables", + "fieldtype": "Section Break", + "label": "Consumables" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "consume_stock", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Stock Consumption", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "eval:doc.consume_stock == 1", + "fieldname": "items", + "fieldtype": "Table", + "ignore_user_permissions": 1, + "label": "Items", + "options": "Clinical Procedure Item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.consume_stock == 1", - "fieldname": "consumables", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consumables", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "sample_collection", + "fieldtype": "Section Break", + "label": "Sample Collection" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Items", - "length": 0, - "no_copy": 0, - "options": "Clinical Procedure Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Sample", + "options": "Lab Test Sample" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "depends_on": "", - "fieldname": "sample_collection", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sample Collection", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "sample.sample_uom", + "fieldname": "sample_uom", + "fieldtype": "Data", + "label": "UOM" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sample", - "length": 0, - "no_copy": 0, - "options": "Lab Test Sample", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample_qty", + "fieldtype": "Float", + "label": "Quantity" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "sample.sample_uom", - "fieldname": "sample_uom", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_21", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Quantity", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample_details", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Collection Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_21", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "change_in_item", + "fieldtype": "Check", + "hidden": 1, + "label": "Change In Item", + "no_copy": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample_details", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Collection Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "change_in_item", - "fieldtype": "Check", - "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": "Change In Item", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "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, - "fieldname": "disabled", - "fieldtype": "Check", - "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": "Disabled", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "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, - "fieldname": "item", - "fieldtype": "Link", - "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": "Item", - "length": 0, - "no_copy": 1, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "item", + "fieldtype": "Link", + "label": "Item", + "no_copy": 1, + "options": "Item", + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-02-12 11:37:18.713344", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedure Template", - "name_case": "", - "owner": "Administrator", + ], + "links": [], + "modified": "2020-02-27 16:32:55.780893", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Clinical Procedure Template", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 - }, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Nursing User", + "share": 1 + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "template", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "template", - "track_changes": 1, - "track_seen": 1, - "track_views": 0 + ], + "restrict_to_domain": "Healthcare", + "search_fields": "template", + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "template", + "track_changes": 1, + "track_seen": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py index 141329b3db1..00fad910a4f 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py @@ -9,26 +9,36 @@ from frappe.model.document import Document from frappe.utils import nowdate class ClinicalProcedureTemplate(Document): - def on_update(self): - #Item and Price List update --> if (change_in_item) - if(self.change_in_item and self.is_billable == 1 and self.item): - updating_item(self) - if(self.rate != 0.0): - updating_rate(self) - elif(self.is_billable == 0 and self.item): - frappe.db.set_value("Item",self.item,"disabled",1) - - frappe.db.set_value(self.doctype,self.name,"change_in_item",0) - self.reload() + def validate(self): + self.enable_disable_item() def after_insert(self): create_item_from_template(self) + def on_update(self): + #Item and Price List update --> if (change_in_item) + if self.change_in_item and self.is_billable == 1 and self.item: + updating_item(self) + if self.rate != 0.0: + updating_rate(self) + elif self.is_billable == 0 and self.item: + frappe.db.set_value('Item',self.item,'disabled',1) + + frappe.db.set_value(self.doctype,self.name,'change_in_item',0) + self.reload() + + def enable_disable_item(self): + if self.is_billable: + if self.disabled: + frappe.db.set_value('Item', self.item, 'disabled', 1) + else: + frappe.db.set_value('Item', self.item, 'disabled', 0) + #Call before delete the template def on_trash(self): if(self.item): try: - frappe.delete_doc("Item",self.item) + frappe.delete_doc('Item',self.item) except Exception: frappe.throw(_("""Not permitted. Please disable the Procedure Template""")) @@ -40,7 +50,7 @@ class ClinicalProcedureTemplate(Document): and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)""", (args.get('item_code'), nowdate()), as_dict = 1) if not item: - frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get('item_code'))) + frappe.throw(_('Item {0} is not active or end of life has been reached').format(args.get('item_code'))) item = item[0] @@ -63,46 +73,47 @@ def updating_rate(self): item_code=%s""",(self.template, self.rate, self.item)) def create_item_from_template(doc): - if(doc.is_billable == 1): + disabled = 1 + + if doc.is_billable: disabled = 0 - else: - disabled = 1 + #insert item item = frappe.get_doc({ - "doctype": "Item", - "item_code": doc.template, - "item_name":doc.template, - "item_group": doc.item_group, - "description":doc.description, - "is_sales_item": 1, - "is_service_item": 1, - "is_purchase_item": 0, - "is_stock_item": 0, - "show_in_website": 0, - "is_pro_applicable": 0, - "disabled": disabled, - "stock_uom": "Unit" + 'doctype': 'Item', + 'item_code': doc.template, + 'item_name':doc.template, + 'item_group': doc.item_group, + 'description':doc.description, + 'is_sales_item': 1, + 'is_service_item': 1, + 'is_purchase_item': 0, + 'is_stock_item': 0, + 'show_in_website': 0, + 'is_pro_applicable': 0, + 'disabled': disabled, + 'stock_uom': 'Unit' }).insert(ignore_permissions=True) #insert item price #get item price list to insert item price if(doc.rate != 0.0): - price_list_name = frappe.db.get_value("Price List", {"selling": 1}) + price_list_name = frappe.db.get_value('Price List', {'selling': 1}) if(doc.rate): make_item_price(item.name, price_list_name, doc.rate) else: make_item_price(item.name, price_list_name, 0.0) #Set item to the template - frappe.db.set_value("Clinical Procedure Template", doc.name, "item", item.name) + frappe.db.set_value('Clinical Procedure Template', doc.name, 'item', item.name) doc.reload() #refresh the doc after insert. def make_item_price(item, price_list_name, item_price): frappe.get_doc({ - "doctype": "Item Price", - "price_list": price_list_name, - "item_code": item, - "price_list_rate": item_price + 'doctype': 'Item Price', + 'price_list': price_list_name, + 'item_code': item, + 'price_list_rate': item_price }).insert(ignore_permissions=True) @frappe.whitelist() @@ -111,20 +122,11 @@ def change_item_code_from_template(item_code, doc): doc = frappe._dict(args) if(frappe.db.exists({ - "doctype": "Item", - "item_code": item_code})): - frappe.throw(_("Code {0} already exist").format(item_code)) + 'doctype': 'Item', + 'item_code': item_code})): + frappe.throw(_('Code {0} already exist').format(item_code)) else: - frappe.rename_doc("Item", doc.item_code, item_code, ignore_permissions = True) - frappe.db.set_value("Clinical Procedure Template", doc.name, "item_code", item_code) + frappe.rename_doc('Item', doc.item_code, item_code, ignore_permissions=True) + frappe.db.set_value('Clinical Procedure Template', doc.name, 'item_code', item_code) return -@frappe.whitelist() -def disable_enable_template(status, name, item_code): - frappe.db.set_value("Clinical Procedure Template", name, "disabled", status) - if (frappe.db.exists({ #set Item's disabled field to status - "doctype": "Item", - "item_code": item_code})): - frappe.db.set_value("Item", item_code, "disabled", status) - - return diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json index f6521183097..6fdc21d388f 100644 --- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json +++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json @@ -78,6 +78,7 @@ }, { "default": "0", + "description": "Checking this will create new Patients with a Disabled status by default and will only be enabled after invoicing the Registration Fee.", "fieldname": "collect_registration_fee", "fieldtype": "Check", "label": "Collect Fee for Patient Registration" diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py index 86094896154..85db0dbabb6 100644 --- a/erpnext/healthcare/doctype/lab_test/lab_test.py +++ b/erpnext/healthcare/doctype/lab_test/lab_test.py @@ -290,19 +290,23 @@ def insert_lab_test_to_medical_record(doc): comment = "" if item.lab_test_comment: comment = str(item.lab_test_comment) - event = "" + table_row = item.lab_test_name + if item.lab_test_event: - event = item.lab_test_event - table_row = item.lab_test_name +" "+ event +" "+ item.result_value + table_row += " " + item.lab_test_event + + if item.result_value: + table_row += " " + item.result_value + if item.normal_range: table_row += " normal_range("+item.normal_range+")" - table_row += " "+comment + table_row += " " + comment elif doc.special_test_items: item = doc.special_test_items[0] if item.lab_test_particulars and item.result_value: - table_row = item.lab_test_particulars +" "+ item.result_value + table_row = item.lab_test_particulars + " " + item.result_value elif doc.sensitivity_test_items: item = doc.sensitivity_test_items[0] diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py index 89f2defb14b..5c9e7524c1a 100644 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py +++ b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe, json from frappe.model.document import Document +from frappe.model.rename_doc import rename_doc from frappe import _ class LabTestTemplate(Document): @@ -98,13 +99,11 @@ def create_item_from_template(doc): # get item price list to insert item price if doc.lab_test_rate != 0.0: price_list_name = frappe.db.get_value("Price List", {"selling": 1}) - if(doc.lab_test_rate): + if doc.lab_test_rate: make_item_price(item.name, price_list_name, doc.lab_test_rate) - item.standard_rate = doc.lab_test_rate else: make_item_price(item.name, price_list_name, 0.0) - item.standard_rate = 0.0 - item.save(ignore_permissions = True) + # Set item in the template frappe.db.set_value("Lab Test Template", doc.name, "item", item.name) diff --git a/erpnext/healthcare/doctype/patient/patient.js b/erpnext/healthcare/doctype/patient/patient.js index 1a34fe8076f..9984b0ae9c9 100644 --- a/erpnext/healthcare/doctype/patient/patient.js +++ b/erpnext/healthcare/doctype/patient/patient.js @@ -15,7 +15,7 @@ frappe.ui.form.on('Patient', { } else { erpnext.toggle_naming_series(); } - if (frappe.defaults.get_default("collect_registration_fee") && frm.doc.disabled == 1) { + if (frappe.defaults.get_default("collect_registration_fee") && frm.doc.status == 'Disabled') { frm.add_custom_button(__('Invoice Patient Registration'), function () { btn_invoice_registration(frm); }); diff --git a/erpnext/healthcare/doctype/patient/patient.json b/erpnext/healthcare/doctype/patient/patient.json index 0136f72f5be..7f97e17934f 100644 --- a/erpnext/healthcare/doctype/patient/patient.json +++ b/erpnext/healthcare/doctype/patient/patient.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_copy": 1, "allow_import": 1, "allow_rename": 1, @@ -19,15 +20,14 @@ "blood_group", "dob", "age_html", - "status", "image", "column_break_14", + "status", "customer", "report_preference", "mobile", "email", "phone", - "disabled", "sb_relation", "patient_relation", "allergy_medical_and_surgical_history", @@ -125,15 +125,15 @@ "report_hide": 1 }, { - "default": "Active", "fieldname": "status", "fieldtype": "Select", - "hidden": 1, + "in_filter": 1, + "in_list_view": 1, "label": "Status", "no_copy": 1, - "options": "Active\nDormant\nOpen", + "options": "Active\nDisabled", "print_hide": 1, - "report_hide": 1 + "read_only": 1 }, { "fieldname": "image", @@ -183,19 +183,8 @@ "fieldname": "phone", "fieldtype": "Data", "in_filter": 1, - "in_list_view": 1, "label": "Phone" }, - { - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "hidden": 1, - "label": "Disabled", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, { "collapsible": 1, "fieldname": "sb_relation", @@ -346,8 +335,9 @@ ], "icon": "fa fa-user", "image_field": "image", + "links": [], "max_attachments": 50, - "modified": "2019-09-25 23:30:49.905893", + "modified": "2020-01-29 11:22:40.698125", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient", diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py index e3eea96f859..420416809dd 100644 --- a/erpnext/healthcare/doctype/patient/patient.py +++ b/erpnext/healthcare/doctype/patient/patient.py @@ -15,8 +15,8 @@ class Patient(Document): def after_insert(self): if(frappe.db.get_value("Healthcare Settings", None, "manage_customer") == '1' and not self.customer): create_customer(self) - if(frappe.db.get_value("Healthcare Settings", None, "collect_registration_fee") == '1'): - frappe.db.set_value("Patient", self.name, "disabled", 1) + if frappe.db.get_single_value('Healthcare Settings', 'collect_registration_fee'): + frappe.db.set_value('Patient', self.name, 'status', 'Disabled') else: send_registration_sms(self) self.reload() @@ -62,7 +62,7 @@ class Patient(Document): return age_str def invoice_patient_registration(self): - frappe.db.set_value("Patient", self.name, "disabled", 0) + frappe.db.set_value("Patient", self.name, "status", "Active") send_registration_sms(self) if(flt(frappe.get_value("Healthcare Settings", None, "registration_fee"))>0): company = frappe.defaults.get_user_default('company') diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js index 858145eef3c..087f1628404 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js @@ -11,7 +11,7 @@ frappe.ui.form.on('Patient Appointment', { refresh: function(frm) { frm.set_query("patient", function () { return { - filters: {"disabled": 0} + filters: {"status": "Active"} }; }); frm.set_query("practitioner", function() { @@ -288,12 +288,19 @@ var check_and_set_availability = function(frm) { }; var get_procedure_prescribed = function(frm){ - if(frm.doc.patient){ + if (frm.doc.patient) { frappe.call({ method:"erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_procedure_prescribed", args: {patient: frm.doc.patient}, - callback: function(r){ - show_procedure_templates(frm, r.message); + callback: function(r) { + if (r.message && r.message.length) { + show_procedure_templates(frm, r.message); + } else { + frappe.msgprint({ + title: __('Not Found'), + message: __('No Prescribed Procedures found for the selected Patient') + }); + } } }); } diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json index ee9f013084b..93124b4de56 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json @@ -1,1177 +1,333 @@ { "allow_copy": 1, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, "allow_import": 1, - "allow_rename": 0, "autoname": "OP-.######", "beta": 1, "creation": "2017-05-04 11:52:40.941507", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Document", - "editable_grid": 0, "engine": "InnoDB", + "field_order": [ + "inpatient_record", + "patient", + "appointment_type", + "duration", + "column_break_1", + "status", + "procedure_template", + "get_procedure_from_encounter", + "procedure_prescription", + "service_unit", + "check_availability", + "section_break_12", + "practitioner", + "department", + "column_break_17", + "appointment_date", + "appointment_time", + "section_break_16", + "patient_name", + "patient_sex", + "column_break_21", + "patient_age", + "section_break_1", + "appointment_datetime", + "mode_of_payment", + "paid_amount", + "column_break_2", + "invoiced", + "company", + "section_break_3", + "notes", + "referring_practitioner", + "reminded" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "patient.inpatient_record", "fieldname": "inpatient_record", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Inpatient Record", - "length": 0, - "no_copy": 0, "options": "Inpatient Record", - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "inpatient_record.patient", "fieldname": "patient", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Patient", - "length": 0, - "no_copy": 0, "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, "search_index": 1, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment_type", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Appointment Type", - "length": 0, - "no_copy": 0, "options": "Appointment Type", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "In Minutes", "fieldname": "duration", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Duration", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Duration" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_1", "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "options": "", - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Scheduled", "depends_on": "eval:!doc.__islocal", "fieldname": "status", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Status", - "length": 0, - "no_copy": 0, "options": "\nScheduled\nOpen\nClosed\nPending\nCancelled", - "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": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "procedure_template", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Procedure", - "length": 0, - "no_copy": 0, "options": "Clinical Procedure Template", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "get_procedure_from_encounter", "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Get prescribed procedures", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Get prescribed procedures" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "procedure_prescription", "fieldtype": "Link", "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": "Procedure Prescription", - "length": 0, "no_copy": 1, "options": "Procedure Prescription", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "print_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "service_unit", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Service Unit", - "length": 0, - "no_copy": 0, "options": "Healthcare Service Unit", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "depends_on": "eval:doc.__islocal", "fieldname": "check_availability", "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Check availability", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Check availability" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_12", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "practitioner", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, "in_standard_filter": 1, "label": "Healthcare Practitioner", - "length": 0, - "no_copy": 0, "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, "search_index": 1, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "department", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Department", - "length": 0, - "no_copy": 0, "options": "Medical Department", - "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": 1, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_17", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment_date", "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment_time", "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Time", - "length": 0, - "no_copy": 0, - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_16", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", "fetch_from": "patient.patient_name", "fieldname": "patient_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Patient Name", - "length": 0, - "no_copy": 0, - "options": "", - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "patient.sex", "fieldname": "patient_sex", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Gender", - "length": 0, "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_21", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "patient_age", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Patient Age", - "length": 0, - "no_copy": 0, - "options": "", - "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 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", "fieldname": "section_break_1", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment_datetime", "fieldtype": "Datetime", - "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": "Date TIme", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", + "label": "Appointment Datetime", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1, + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "mode_of_payment", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Mode of Payment", - "length": 0, - "no_copy": 0, - "options": "Mode of Payment", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Mode of Payment" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "paid_amount", "fieldtype": "Currency", - "hidden": 0, - "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": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Paid Amount" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "fieldname": "invoiced", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Invoiced", - "length": 0, - "no_copy": 0, - "options": "", - "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": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "company", "fieldtype": "Link", "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": "Company", - "length": 0, "no_copy": 1, "options": "Company", - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, "collapsible": 1, - "columns": 0, "fieldname": "section_break_3", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "More Info", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "More Info" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "notes", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Notes", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Notes" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "referring_practitioner", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Referring Practitioner", - "length": 0, - "no_copy": 0, "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "fieldname": "reminded", "fieldtype": "Check", "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": "Reminded", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-11-14 13:24:01.529536", - "modified_by": "Administrator", + "modified": "2020-03-27 15:55:24.344945", + "modified_by": "ruchamahabal2@gmail.com", "module": "Healthcare", "name": "Patient Appointment", - "name_case": "", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Healthcare Administrator", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Physician", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Nursing User", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 } ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, "restrict_to_domain": "Healthcare", "search_fields": "patient, practitioner, department, appointment_date, appointment_time", "show_name_in_global_search": 1, @@ -1179,6 +335,5 @@ "sort_order": "DESC", "title_field": "patient", "track_changes": 1, - "track_seen": 1, - "track_views": 0 -} + "track_seen": 1 +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py index 12248fcdce3..8f3602af67e 100755 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py @@ -25,6 +25,7 @@ class PatientAppointment(Document): self.reload() def validate(self): + self.set_appointment_datetime() end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) + datetime.timedelta(minutes=float(self.duration)) overlaps = frappe.db.sql(""" select @@ -44,6 +45,9 @@ class PatientAppointment(Document): frappe.throw(_("""Appointment overlaps with {0}.
{1} has appointment scheduled with {2} at {3} having {4} minute(s) duration.""").format(overlaps[0][0], overlaps[0][1], overlaps[0][2], overlaps[0][3], overlaps[0][4])) + def set_appointment_datetime(self): + self.appointment_datetime = "%s %s" % (self.appointment_date, self.appointment_time or "00:00:00") + def after_insert(self): if self.procedure_prescription: frappe.db.set_value("Procedure Prescription", self.procedure_prescription, "appointment_booked", True) @@ -319,27 +323,29 @@ def create_encounter(appointment): return encounter.as_dict() -def remind_appointment(): - if frappe.db.get_value("Healthcare Settings", None, "app_rem") == '1': - rem_before = datetime.datetime.strptime(frappe.get_value("Healthcare Settings", None, "rem_before"), "%H:%M:%S") - rem_dt = datetime.datetime.now() + datetime.timedelta( - hours=rem_before.hour, minutes=rem_before.minute, seconds=rem_before.second) +def set_appointment_reminder(): + if frappe.db.get_single_value("Healthcare Settings", "app_rem"): + remind_before = datetime.datetime.strptime(frappe.db.get_single_value("Healthcare Settings", "rem_before"), '%H:%M:%S') - appointment_list = frappe.db.sql( - "select name from `tabPatient Appointment` where start_dt between %s and %s and reminded = 0 ", - (datetime.datetime.now(), rem_dt) - ) + reminder_dt = datetime.datetime.now() + datetime.timedelta( + hours=remind_before.hour, minutes=remind_before.minute, seconds=remind_before.second) - for i in range(0, len(appointment_list)): - doc = frappe.get_doc("Patient Appointment", appointment_list[i][0]) - message = frappe.db.get_value("Healthcare Settings", None, "app_rem_msg") + appointment_list = frappe.db.get_all("Patient Appointment", { + "appointment_datetime": ["between", (datetime.datetime.now(), reminder_dt)], + "reminded": 0, + "status": ["!=", "Cancelled"] + }) + + for appointment in appointment_list: + doc = frappe.get_doc('Patient Appointment', appointment.name) + message = frappe.db.get_single_value("Healthcare Settings", "app_rem_msg") send_message(doc, message) - frappe.db.set_value("Patient Appointment", doc.name, "reminded",1) + frappe.db.set_value('Patient Appointment', doc.name, 'reminded', 1) def send_message(doc, message): - patient = frappe.get_doc("Patient", doc.patient) - if patient.mobile: + patient_mobile = frappe.db.get_value("Patient", doc.patient, "mobile") + if patient_mobile: context = {"doc": doc, "alert": doc, "comments": None} if doc.get("_comments"): context["comments"] = json.loads(doc.get("_comments")) diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js index 088bc8161b1..c1b0b18dba4 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js @@ -62,7 +62,7 @@ frappe.ui.form.on('Patient Encounter', { frm.set_query("patient", function () { return { - filters: {"disabled": 0} + filters: {"status": "Active"} }; }); frm.set_query("drug_code", "drug_prescription", function() { diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json index 08a1b86969c..cff100cc704 100644 --- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json +++ b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json @@ -1,160 +1,71 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:schedule_name", - "beta": 1, - "creation": "2017-05-03 17:28:03.926787", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:schedule_name", + "beta": 1, + "creation": "2017-05-03 17:28:03.926787", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "disabled", + "schedule_details_section", + "schedule_name", + "time_slots" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "schedule_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Schedule Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "schedule_name", + "fieldtype": "Data", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Schedule Name", + "reqd": 1, + "unique": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "time_slots", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Time Slots", - "length": 0, - "no_copy": 0, - "options": "Healthcare Schedule Time Slot", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "time_slots", + "fieldtype": "Table", + "label": "Time Slots", + "options": "Healthcare Schedule Time Slot" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "disabled", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Disabled", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled", + "print_hide": 1 + }, + { + "fieldname": "schedule_details_section", + "fieldtype": "Section Break", + "label": "Schedule Details" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-06-29 14:55:34.795995", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Practitioner Schedule", - "name_case": "", - "owner": "rmehta@gmail.com", + ], + "links": [], + "modified": "2020-01-31 12:21:45.975488", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Practitioner Schedule", + "owner": "rmehta@gmail.com", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "restrict_to_domain": "Healthcare", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 7f268d6ba14..81fb40506b6 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -268,7 +268,9 @@ doc_events = { scheduler_events = { "all": [ - "erpnext.projects.doctype.project.project.project_status_update_reminder" + "erpnext.projects.doctype.project.project.project_status_update_reminder", + "erpnext.healthcare_healthcare.doctype.patient_appointment.patient_appointment.send_appointment_reminder" + ], "hourly": [ 'erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails', From e4cb523181ce36250b090ffd720c90059649a220 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 31 Mar 2020 15:26:24 +0530 Subject: [PATCH 135/137] fix: serial no scan not adding the serial nos in stock entry (#21082) --- erpnext/public/js/controllers/transaction.js | 7 ++++++- .../stock/doctype/stock_entry/stock_entry.js | 17 +++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ee8ca0d5662..e1c38a91297 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -362,12 +362,17 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ ['serial_no', 'batch_no', 'barcode'].forEach(field => { if (data[field] && frappe.meta.has_field(row_to_modify.doctype, field)) { + + let value = (row_to_modify[field] && field === "serial_no") + ? row_to_modify[field] + '\n' + data[field] : data[field]; + frappe.model.set_value(row_to_modify.doctype, - row_to_modify.name, field, data[field]); + row_to_modify.name, field, value); } }); scan_barcode_field.set_value(''); + refresh_field("items"); }); } return false; diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index 23ee9f472b8..b54233f4585 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -303,12 +303,12 @@ frappe.ui.form.on('Stock Entry', { method: "erpnext.stock.get_item_details.get_serial_no", args: {"args": args}, callback: function(r) { - if (!r.exe){ + if (!r.exe && r.message){ frappe.model.set_value(cdt, cdn, "serial_no", r.message); - } - if (callback) { - callback(); + if (callback) { + callback(); + } } } }); @@ -537,10 +537,15 @@ frappe.ui.form.on('Stock Entry Detail', { if(r.message) { var d = locals[cdt][cdn]; $.each(r.message, function(k, v) { - frappe.model.set_value(cdt, cdn, k, v); // qty and it's subsequent fields weren't triggered + if (v) { + frappe.model.set_value(cdt, cdn, k, v); // qty and it's subsequent fields weren't triggered + } }); refresh_field("items"); - erpnext.stock.select_batch_and_serial_no(frm, d); + + if (!d.serial_no) { + erpnext.stock.select_batch_and_serial_no(frm, d); + } } } }); From c5a3bcca70fa2657064c55408ed04f6828348e14 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 31 Mar 2020 15:28:15 +0530 Subject: [PATCH 136/137] fix: make for quantity as non mandatory in job card (#21080) --- erpnext/manufacturing/doctype/bom/bom.js | 1 + .../doctype/job_card/job_card.js | 14 ++- .../doctype/job_card/job_card.json | 111 ++++++++---------- .../doctype/job_card/job_card.py | 38 +++--- .../doctype/work_order/work_order.py | 3 +- 5 files changed, 80 insertions(+), 87 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 3acaee4ffbd..4f08bbc3fc7 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -135,6 +135,7 @@ frappe.ui.form.on("BOM", { frappe.call({ method: "erpnext.manufacturing.doctype.work_order.work_order.make_work_order", args: { + bom_no: frm.doc.name, item: frm.doc.item, qty: data.qty || 0.0, project: frm.doc.project diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 6db8f2f5b38..9ee5e80f88d 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -24,7 +24,7 @@ frappe.ui.form.on('Job Card', { } } - if (frm.doc.docstatus == 0 && frm.doc.for_quantity > frm.doc.total_completed_qty + if (frm.doc.docstatus == 0 && (frm.doc.for_quantity > frm.doc.total_completed_qty || !frm.doc.for_quantity) && (!frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) { frm.trigger("prepare_timer_buttons"); } @@ -63,10 +63,14 @@ frappe.ui.form.on('Job Card', { let completed_time = frappe.datetime.now_datetime(); frm.trigger("hide_timer"); - frappe.prompt({fieldtype: 'Float', label: __('Completed Quantity'), - fieldname: 'qty', reqd: 1, default: frm.doc.for_quantity}, data => { - frm.events.complete_job(frm, completed_time, data.qty); - }, __("Enter Value"), __("Complete")); + if (frm.doc.for_quantity) { + frappe.prompt({fieldtype: 'Float', label: __('Completed Quantity'), + fieldname: 'qty', reqd: 1, default: frm.doc.for_quantity}, data => { + frm.events.complete_job(frm, completed_time, data.qty); + }, __("Enter Value"), __("Complete")); + } else { + frm.events.complete_job(frm, completed_time, 0); + } }).addClass("btn-primary"); } }, diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json index fd39af1faad..7661fffa864 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.json +++ b/erpnext/manufacturing/doctype/job_card/job_card.json @@ -99,8 +99,7 @@ "fieldname": "for_quantity", "fieldtype": "Float", "in_list_view": 1, - "label": "Qty To Manufacture", - "reqd": 1 + "label": "Qty To Manufacture" }, { "fieldname": "wip_warehouse", @@ -122,6 +121,7 @@ "options": "Employee" }, { + "allow_bulk_edit": 1, "fieldname": "time_logs", "fieldtype": "Table", "label": "Time Logs", @@ -290,78 +290,61 @@ } ], "is_submittable": 1, - "modified": "2020-03-24 13:08:57.926201", + "modified": "2020-03-27 13:36:35.417502", "modified_by": "Administrator", "module": "Manufacturing", "name": "Job Card", "owner": "Administrator", "permissions": [ { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "submit": 1, "write": 1 - }, + }, { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Manufacturing User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Manufacturing User", + "share": 1, + "submit": 1, "write": 1 - }, + }, { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Manufacturing Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Manufacturing Manager", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "operation", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "operation", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index eec7d242871..7c648c79014 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -92,10 +92,7 @@ class JobCard(Document): if not self.time_logs: frappe.throw(_("Time logs are required for job card {0}").format(self.name)) - if self.total_completed_qty <= 0.0: - frappe.throw(_("Total completed qty must be greater than zero")) - - if self.total_completed_qty != self.for_quantity: + if self.for_quantity and self.total_completed_qty != self.for_quantity: frappe.throw(_("The total completed qty({0}) must be equal to qty to manufacture({1})" .format(frappe.bold(self.total_completed_qty),frappe.bold(self.for_quantity)))) @@ -106,27 +103,34 @@ class JobCard(Document): for_quantity, time_in_mins = 0, 0 from_time_list, to_time_list = [], [] - for d in frappe.get_all('Job Card', - filters = {'docstatus': 1, 'operation_id': self.operation_id}): - doc = frappe.get_doc('Job Card', d.name) - for_quantity += doc.total_completed_qty - time_in_mins += doc.total_time_in_mins - for time_log in doc.time_logs: - if time_log.from_time: - from_time_list.append(time_log.from_time) - if time_log.to_time: - to_time_list.append(time_log.to_time) + data = frappe.get_all('Job Card', + fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"], + filters = {"docstatus": 1, "work_order": self.work_order, + "workstation": self.workstation, "operation": self.operation}) + + if data and len(data) > 0: + for_quantity = data[0].completed_qty + time_in_mins = data[0].time_in_mins if for_quantity: + time_data = frappe.db.sql(""" + SELECT + min(from_time) as start_time, max(to_time) as end_time + FROM `tabJob Card` jc, `tabJob Card Time Log` jctl + WHERE + jctl.parent = jc.name and jc.work_order = %s + and jc.workstation = %s and jc.operation = %s and jc.docstatus = 1 + """, (self.work_order, self.workstation, self.operation), as_dict=1) + wo = frappe.get_doc('Work Order', self.work_order) for data in wo.operations: - if data.name == self.operation_id: + if data.workstation == self.workstation and data.operation == self.operation: data.completed_qty = for_quantity data.actual_operation_time = time_in_mins - data.actual_start_time = min(from_time_list) if from_time_list else None - data.actual_end_time = max(to_time_list) if to_time_list else None + data.actual_start_time = time_data[0].start_time if time_data else None + data.actual_end_time = time_data[0].end_time if time_data else None wo.flags.ignore_validate_update_after_submit = True wo.update_operation_status() diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index bd2ae6c36b1..8a39f7420e9 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -609,7 +609,7 @@ def get_item_details(item, project = None): return res @frappe.whitelist() -def make_work_order(item, qty=0, project=None): +def make_work_order(bom_no, item, qty=0, project=None): if not frappe.has_permission("Work Order", "write"): frappe.throw(_("Not permitted"), frappe.PermissionError) @@ -618,6 +618,7 @@ def make_work_order(item, qty=0, project=None): wo_doc = frappe.new_doc("Work Order") wo_doc.production_item = item wo_doc.update(item_details) + wo_doc.bom_no = bom_no if flt(qty) > 0: wo_doc.qty = flt(qty) From 798d532a11bf93f7a8e393308e4de425c2fb7d14 Mon Sep 17 00:00:00 2001 From: Saqib Date: Tue, 31 Mar 2020 15:30:53 +0530 Subject: [PATCH 137/137] =?UTF-8?q?fix:=20warehouse=5Faccount=5Fmap=20not?= =?UTF-8?q?=20getting=20reset=20for=20diff=20company=20transac=E2=80=A6=20?= =?UTF-8?q?(#20997)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: warehouse_account_map not getting reset for diff company transaction * fix: potential key errors while fetching warehouse_account_map * fix: travis Co-authored-by: Nabin Hait --- erpnext/stock/__init__.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/__init__.py b/erpnext/stock/__init__.py index a4d4cbd8ef8..8d64efe41dd 100644 --- a/erpnext/stock/__init__.py +++ b/erpnext/stock/__init__.py @@ -13,12 +13,16 @@ install_docs = [ ] def get_warehouse_account_map(company=None): - if not frappe.flags.warehouse_account_map or frappe.flags.in_test: + company_warehouse_account_map = company and frappe.flags.setdefault('warehouse_account_map', {}).get(company) + warehouse_account_map = frappe.flags.warehouse_account_map + + if not warehouse_account_map or not company_warehouse_account_map or frappe.flags.in_test: warehouse_account = frappe._dict() filters = {} if company: filters['company'] = company + frappe.flags.setdefault('warehouse_account_map', {}).setdefault(company, {}) for d in frappe.get_all('Warehouse', fields = ["name", "account", "parent_warehouse", "company", "is_group"], @@ -30,10 +34,12 @@ def get_warehouse_account_map(company=None): if d.account: d.account_currency = frappe.db.get_value('Account', d.account, 'account_currency', cache=True) warehouse_account.setdefault(d.name, d) - - frappe.flags.warehouse_account_map = warehouse_account - - return frappe.flags.warehouse_account_map + if company: + frappe.flags.warehouse_account_map[company] = warehouse_account + else: + frappe.flags.warehouse_account_map = warehouse_account + + return frappe.flags.warehouse_account_map.get(company) or frappe.flags.warehouse_account_map def get_warehouse_account(warehouse, warehouse_account=None): account = warehouse.account
-

+

${__("Projected Quantity Formula")} diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index 0be9f1a8eef..af844816e8b 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -1,1391 +1,321 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 0, - "creation": "2017-10-29 11:53:09.523362", - "custom": 0, - "default_print_format": "", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, - "engine": "InnoDB", + "actions": [], + "autoname": "naming_series:", + "creation": "2017-10-29 11:53:09.523362", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "naming_series", + "company", + "get_items_from", + "column_break1", + "posting_date", + "filters", + "item_code", + "customer", + "warehouse", + "project", + "column_break2", + "from_date", + "to_date", + "sales_orders_detail", + "get_sales_orders", + "sales_orders", + "material_request_detail", + "get_material_request", + "material_requests", + "select_items_to_manufacture_section", + "get_items", + "po_items", + "material_request_planning", + "include_non_stock_items", + "include_subcontracted_items", + "ignore_existing_ordered_qty", + "column_break_25", + "for_warehouse", + "download_materials_required", + "get_items_for_mr", + "section_break_27", + "mr_items", + "other_details", + "total_planned_qty", + "total_produced_qty", + "column_break_32", + "status", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fetch_if_empty": 0, - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Naming Series", - "length": 0, - "no_copy": 0, - "options": "MFG-PP-.YYYY.-", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Naming Series", + "options": "MFG-PP-.YYYY.-", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fetch_if_empty": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Company", + "options": "Company", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fetch_if_empty": 0, - "fieldname": "get_items_from", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Get Items From", - "length": 0, - "no_copy": 0, - "options": "\nSales Order\nMaterial Request", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "get_items_from", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Get Items From", + "options": "\nSales Order\nMaterial Request" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break1", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fetch_if_empty": 0, - "fieldname": "posting_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Posting Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Today", + "fieldname": "posting_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Posting Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "columns": 0, - "depends_on": "eval: doc.get_items_from", - "description": "", - "fetch_if_empty": 0, - "fieldname": "filters", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Filters", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", + "depends_on": "eval: doc.get_items_from", + "fieldname": "filters", + "fieldtype": "Section Break", + "label": "Filters" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "item_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 0, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Code", + "options": "Item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Sales Order\"", - "fetch_if_empty": 0, - "fieldname": "customer", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Customer", - "length": 0, - "no_copy": 0, - "options": "Customer", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", + "fieldname": "customer", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Customer", + "options": "Customer" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Material Request\"", - "fetch_if_empty": 0, - "fieldname": "warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "eval: doc.get_items_from == \"Material Request\"", + "fieldname": "warehouse", + "fieldtype": "Link", + "label": "Warehouse", + "options": "Warehouse" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Sales Order\"", - "fetch_if_empty": 0, - "fieldname": "project", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Project", - "length": 0, - "no_copy": 0, - "options": "Project", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "column_break2", + "fieldtype": "Column Break", "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "from_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "From Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "from_date", + "fieldtype": "Date", + "label": "From Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "to_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "To Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "to_date", + "fieldtype": "Date", + "label": "To Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Sales Order\"", - "fetch_if_empty": 0, - "fieldname": "sales_orders_detail", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sales Orders Detail", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", + "depends_on": "eval: doc.get_items_from == \"Sales Order\"", + "fieldname": "sales_orders_detail", + "fieldtype": "Section Break", + "label": "Sales Orders" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fetch_if_empty": 0, - "fieldname": "get_sales_orders", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Get Sales Orders", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "get_sales_orders", + "fieldtype": "Button", + "label": "Get Sales Orders" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "sales_orders", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sales Orders", - "length": 0, - "no_copy": 1, - "options": "Production Plan Sales Order", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sales_orders", + "fieldtype": "Table", + "label": "Sales Orders", + "no_copy": 1, + "options": "Production Plan Sales Order" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "columns": 0, - "depends_on": "eval: doc.get_items_from == \"Material Request\"", - "fetch_if_empty": 0, - "fieldname": "material_request_detail", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Material Request Detail", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "collapsible_depends_on": "eval: doc.__islocal", + "depends_on": "eval: doc.get_items_from == \"Material Request\"", + "fieldname": "material_request_detail", + "fieldtype": "Section Break", + "label": "Material Request Detail" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fetch_if_empty": 0, - "fieldname": "get_material_request", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Get Material Request", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "get_material_request", + "fieldtype": "Button", + "label": "Get Material Request" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "material_requests", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Material Requests", - "length": 0, - "no_copy": 1, - "options": "Production Plan Material Request", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "material_requests", + "fieldtype": "Table", + "label": "Material Requests", + "no_copy": 1, + "options": "Production Plan Material Request" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fetch_if_empty": 0, - "fieldname": "select_items_to_manufacture_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Select Items to Manufacture", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "select_items_to_manufacture_section", + "fieldtype": "Section Break", + "label": "Select Items to Manufacture" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "get_items_from", - "fetch_if_empty": 0, - "fieldname": "get_items", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Get Items For Work Order", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "get_items_from", + "fieldname": "get_items", + "fieldtype": "Button", + "label": "Get Items For Work Order" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "po_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 1, - "options": "Production Plan Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "po_items", + "fieldtype": "Table", + "no_copy": 1, + "options": "Production Plan Item", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fetch_if_empty": 0, - "fieldname": "material_request_planning", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Material Request Planning", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "material_request_planning", + "fieldtype": "Section Break", + "label": "Material Request Planning" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "include_non_stock_items", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Include Non Stock Items", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "include_non_stock_items", + "fieldtype": "Check", + "label": "Include Non Stock Items" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "include_subcontracted_items", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Include Subcontracted Items", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "include_subcontracted_items", + "fieldtype": "Check", + "label": "Include Subcontracted Items" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "If enabled, then system will create the material even if the raw materials are available", - "fetch_if_empty": 0, - "fieldname": "ignore_existing_ordered_qty", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Ignore Existing Projected Quantity", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "description": "To know more about projected quantity, click here.", + "fieldname": "ignore_existing_ordered_qty", + "fieldtype": "Check", + "label": "Ignore Existing Projected Quantity" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break_25", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_25", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "for_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "For Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "for_warehouse", + "fieldtype": "Link", + "label": "For Warehouse", + "options": "Warehouse" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "download_materials_required", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Download Materials Required", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "download_materials_required", + "fieldtype": "Button", + "label": "Download Required Materials" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "get_items_for_mr", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Get Raw Materials For Production", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "get_items_for_mr", + "fieldtype": "Button", + "label": "Get Raw Materials For Production" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fetch_if_empty": 0, - "fieldname": "section_break_27", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_27", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "mr_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Material Request Plan Item", - "length": 0, - "no_copy": 1, - "options": "Material Request Plan Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "mr_items", + "fieldtype": "Table", + "label": "Material Request Plan Item", + "no_copy": 1, + "options": "Material Request Plan Item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fetch_if_empty": 0, - "fieldname": "projected_qty_formula", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Projected Qty Formula", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "other_details", + "fieldtype": "Section Break", + "label": "Other Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "other_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Other Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "total_planned_qty", + "fieldtype": "Float", + "label": "Total Planned Qty", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fetch_if_empty": 0, - "fieldname": "total_planned_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Total Planned Qty", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "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 - }, + "default": "0", + "fieldname": "total_produced_qty", + "fieldtype": "Float", + "label": "Total Produced Qty", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fetch_if_empty": 0, - "fieldname": "total_produced_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Total Produced Qty", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "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 - }, + "fieldname": "column_break_32", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break_32", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "label": "Status", + "no_copy": 1, + "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled\nMaterial Requested", + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Draft", - "fetch_if_empty": 0, - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 1, - "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled\nMaterial Requested", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "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, - "fetch_if_empty": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amended From", - "length": 0, - "no_copy": 1, - "options": "Production Plan", - "permlevel": 0, - "print_hide": 1, - "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 + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Production Plan", + "print_hide": 1, + "read_only": 1 } - ], - "has_web_view": 0, - "hide_toolbar": 0, - "icon": "fa fa-calendar", - "idx": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-04-09 12:05:14.300886", - "modified_by": "Administrator", - "module": "Manufacturing", - "name": "Production Plan", - "name_case": "", - "owner": "Administrator", + ], + "icon": "fa fa-calendar", + "is_submittable": 1, + "links": [], + "modified": "2019-12-04 15:58:50.940460", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Production Plan", + "owner": "Administrator", "permissions": [ { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 0, - "role": "Manufacturing User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "Manufacturing User", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "ASC", - "title_field": "", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py index 91c28555d61..09ec24a67a2 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py @@ -6,7 +6,7 @@ def get_data(): 'fieldname': 'production_plan', 'transactions': [ { - 'label': _('Related'), + 'label': _('Transactions'), 'items': ['Work Order', 'Material Request'] }, ] diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index 7e1ea3eb1d9..1989c10c394 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -6,7 +6,7 @@ frappe.ui.form.on("Work Order", { frm.custom_make_buttons = { 'Stock Entry': 'Start', 'Pick List': 'Create Pick List', - 'Job Card': 'Create Job Card', + 'Job Card': 'Create Job Card' }; // Set query for warehouses @@ -132,7 +132,8 @@ frappe.ui.form.on("Work Order", { } if (frm.doc.docstatus===1) { - frm.trigger('show_progress'); + frm.trigger('show_progress_for_items'); + frm.trigger('show_progress_for_operations'); } if (frm.doc.docstatus === 1 @@ -180,89 +181,72 @@ frappe.ui.form.on("Work Order", { make_job_card: function(frm) { let qty = 0; - const fields = [{ - fieldtype: "Link", - fieldname: "operation", - options: "Operation", - label: __("Operation"), - get_query: () => { - const filter_workstation = frm.doc.operations.filter(d => { - if (d.status != "Completed") { - return d; - } - }); + let operations_data = []; - return { - filters: { - name: ["in", (filter_workstation || []).map(d => d.operation)] - } - }; - }, - reqd: true - }, { - fieldtype: "Link", - fieldname: "workstation", - options: "Workstation", - label: __("Workstation"), - get_query: () => { - const operation = dialog.get_value("operation"); - const filter_workstation = frm.doc.operations.filter(d => { - if (d.operation == operation) { - return d; - } - }); - - return { - filters: { - name: ["in", (filter_workstation || []).map(d => d.workstation)] - } - }; - }, - onchange: () => { - const operation = dialog.get_value("operation"); - const workstation = dialog.get_value("workstation"); - if (operation && workstation) { - const row = frm.doc.operations.filter(d => d.operation == operation && d.workstation == workstation)[0]; - qty = frm.doc.qty - row.completed_qty; - - if (qty > 0) { - dialog.set_value("qty", qty); - } - } - }, - reqd: true - }, { - fieldtype: "Float", - fieldname: "qty", - label: __("For Quantity"), - reqd: true - }]; - - const dialog = frappe.prompt(fields, function(data) { - if (data.qty > qty) { - frappe.throw(__("For Quantity must be less than quantity {0}", [qty])); + const dialog = frappe.prompt({fieldname: 'operations', fieldtype: 'Table', label: __('Operations'), + fields: [ + { + fieldtype:'Link', + fieldname:'operation', + label: __('Operation'), + read_only:1, + in_list_view:1 + }, + { + fieldtype:'Link', + fieldname:'workstation', + label: __('Workstation'), + read_only:1, + in_list_view:1 + }, + { + fieldtype:'Data', + fieldname:'name', + label: __('Operation Id') + }, + { + fieldtype:'Float', + fieldname:'pending_qty', + label: __('Pending Qty'), + }, + { + fieldtype:'Float', + fieldname:'qty', + label: __('Quantity to Manufacture'), + read_only:0, + in_list_view:1, + }, + ], + data: operations_data, + in_place_edit: true, + get_data: function() { + return operations_data; } - - if (data.qty <= 0) { - frappe.throw(__("For Quantity must be greater than zero")); - } - + }, function(data) { frappe.call({ method: "erpnext.manufacturing.doctype.work_order.work_order.make_job_card", args: { work_order: frm.doc.name, - operation: data.operation, - workstation: data.workstation, - qty: data.qty - }, - callback: function(r){ - if (r.message) { - var doc = frappe.model.sync(r.message)[0]; - frappe.set_route("Form", doc.doctype, doc.name); - } + operations: data.operations, } }); - }, __("For Job Card")); + }, __("Job Card"), __("Create")); + + var pending_qty = 0; + frm.doc.operations.forEach(data => { + if(data.completed_qty != frm.doc.qty) { + pending_qty = frm.doc.qty - flt(data.completed_qty); + + dialog.fields_dict.operations.df.data.push({ + 'name': data.name, + 'operation': data.operation, + 'workstation': data.workstation, + 'qty': pending_qty, + 'pending_qty': pending_qty, + }); + } + }); + dialog.fields_dict.operations.grid.refresh(); }, make_bom: function(frm) { @@ -278,7 +262,7 @@ frappe.ui.form.on("Work Order", { }); }, - show_progress: function(frm) { + show_progress_for_items: function(frm) { var bars = []; var message = ''; var added_min = false; @@ -312,6 +296,44 @@ frappe.ui.form.on("Work Order", { frm.dashboard.add_progress(__('Status'), bars, message); }, + show_progress_for_operations: function(frm) { + if (frm.doc.operations && frm.doc.operations.length) { + + let progress_class = { + "Work in Progress": "progress-bar-warning", + "Completed": "progress-bar-success" + }; + + let bars = []; + let message = ''; + let title = ''; + let status_wise_oprtation_data = {}; + let total_completed_qty = frm.doc.qty * frm.doc.operations.length; + + frm.doc.operations.forEach(d => { + if (!status_wise_oprtation_data[d.status]) { + status_wise_oprtation_data[d.status] = [d.completed_qty, d.operation]; + } else { + status_wise_oprtation_data[d.status][0] += d.completed_qty; + status_wise_oprtation_data[d.status][1] += ', ' + d.operation; + } + }); + + for (let key in status_wise_oprtation_data) { + title = __("{0} Operations: {1}", [key, status_wise_oprtation_data[key][1].bold()]); + bars.push({ + 'title': title, + 'width': status_wise_oprtation_data[key][0] / total_completed_qty * 100 + '%', + 'progress_class': progress_class[key] + }); + + message += title + '. '; + } + + frm.dashboard.add_progress(__('Status'), bars, message); + } + }, + production_item: function(frm) { if (frm.doc.production_item) { frappe.call({ diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json index 0d073a2312b..6152fbb8402 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.json +++ b/erpnext/manufacturing/doctype/work_order/work_order.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "autoname": "naming_series:", "creation": "2013-01-10 16:34:16", @@ -468,7 +469,8 @@ "idx": 1, "image_field": "image", "is_submittable": 1, - "modified": "2019-08-28 12:29:35.315239", + "links": [], + "modified": "2019-12-04 11:20:04.695123", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order", diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 28bcc2e0f9c..83579414812 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -6,7 +6,7 @@ import frappe import json import math from frappe import _ -from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate +from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate, get_link_to_form from frappe.model.document import Document from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items_as_dict from dateutil.relativedelta import relativedelta @@ -711,21 +711,41 @@ def query_sales_order(production_item): return out @frappe.whitelist() -def make_job_card(work_order, operation, workstation, qty=0): +def make_job_card(work_order, operations): + if isinstance(operations, string_types): + operations = json.loads(operations) + work_order = frappe.get_doc('Work Order', work_order) - row = get_work_order_operation_data(work_order, operation, workstation) - if row: - return create_job_card(work_order, row, qty) + for row in operations: + validate_operation_data(row) + create_job_card(work_order, row, row.get("qty"), auto_create=True) + +def validate_operation_data(row): + if row.get("qty") <= 0: + frappe.throw(_("Quantity to Manufacture can not be zero for the operation {0}") + .format( + frappe.bold(row.get("operation")) + ) + ) + + if row.get("qty") > row.get("pending_qty"): + frappe.throw(_("For operation {0}: Quantity ({1}) can not be greter than pending quantity({2})") + .format( + frappe.bold(row.get("operation")), + frappe.bold(row.get("qty")), + frappe.bold(row.get("pending_qty")) + ) + ) def create_job_card(work_order, row, qty=0, auto_create=False): doc = frappe.new_doc("Job Card") doc.update({ 'work_order': work_order.name, - 'operation': row.operation, - 'workstation': row.workstation, + 'operation': row.get("operation"), + 'workstation': row.get("workstation"), 'posting_date': nowdate(), 'for_quantity': qty or work_order.get('qty', 0), - 'operation_id': row.name, + 'operation_id': row.get("name"), 'bom_no': work_order.bom_no, 'project': work_order.project, 'company': work_order.company, @@ -738,7 +758,7 @@ def create_job_card(work_order, row, qty=0, auto_create=False): if auto_create: doc.flags.ignore_mandatory = True doc.insert() - frappe.msgprint(_("Job card {0} created").format(doc.name)) + frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name))) return doc diff --git a/erpnext/manufacturing/doctype/work_order/work_order_calendar.js b/erpnext/manufacturing/doctype/work_order/work_order_calendar.js index c44b1e2700d..7ce05e9b881 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order_calendar.js +++ b/erpnext/manufacturing/doctype/work_order/work_order_calendar.js @@ -2,11 +2,13 @@ // For license information, please see license.txt frappe.views.calendar["Work Order"] = { + fields: ["planned_start_date", "planned_end_date", "status", "produced_qty", "qty", "name", "name"], field_map: { "start": "planned_start_date", "end": "planned_end_date", "id": "name", "title": "name", + "status": "status", "allDay": "allDay", "progress": function(data) { return flt(data.produced_qty) / data.qty * 100; diff --git a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py index 0d3c30ea6eb..87c090f99c3 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py +++ b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py @@ -6,7 +6,8 @@ def get_data(): 'fieldname': 'work_order', 'transactions': [ { - 'items': ['Pick List', 'Stock Entry', 'Job Card'] + 'label': _('Transactions'), + 'items': ['Stock Entry', 'Job Card', 'Pick List'] } ] } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json index 75d42cd061e..3f5e18e8130 100644 --- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json +++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2014-10-16 14:35:41.950175", "doctype": "DocType", "editable_grid": 1, @@ -68,6 +69,7 @@ "description": "Operation completed for how many finished goods?", "fieldname": "completed_qty", "fieldtype": "Float", + "in_list_view": 1, "label": "Completed Qty", "no_copy": 1, "read_only": 1 @@ -188,8 +190,9 @@ } ], "istable": 1, - "modified": "2019-07-16 23:01:07.720337", - "modified_by": "govindsmenokee@gmail.com", + "links": [], + "modified": "2019-12-03 19:24:29.594189", + "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order Operation", "owner": "Administrator", @@ -197,4 +200,4 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 -} +} \ No newline at end of file From 1e7cba9dd39a3890944bacb8bcf31a1fc6342c9c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 24 Mar 2020 15:43:21 +0530 Subject: [PATCH 110/137] fix: Default dimension set code cleanup --- .../public/js/utils/dimension_tree_filter.js | 69 +++++++++---------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js index 8b6de0f5179..75c5a820b46 100644 --- a/erpnext/public/js/utils/dimension_tree_filter.js +++ b/erpnext/public/js/utils/dimension_tree_filter.js @@ -1,23 +1,25 @@ frappe.provide('frappe.ui.form'); -erpnext.doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset", +let default_dimensions = {}; + +let doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset", "Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Shipping Rule", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"]; -erpnext.child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", +let child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction", "Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"]; frappe.call({ method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters", - callback: function(r){ + callback: function(r) { erpnext.dimension_filters = r.message[0]; - erpnext.default_dimensions = r.message[1]; + default_dimensions = r.message[1]; } }); -erpnext.doctypes_with_dimensions.forEach((doctype) => { +doctypes_with_dimensions.forEach((doctype) => { frappe.ui.form.on(doctype, { onload: function(frm) { erpnext.dimension_filters.forEach((dimension) => { @@ -27,41 +29,40 @@ erpnext.doctypes_with_dimensions.forEach((doctype) => { "is_group": 0 }); } - - if (Object.keys(erpnext.default_dimensions).length > 0) { - if (frappe.meta.has_field(doctype, dimension['fieldname'])) { - if (frm.is_new() && frappe.meta.has_field(doctype, 'company') && frm.doc.company) { - frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]); - } - } - - if (frm.doc.items && frm.doc.items.length && frm.doc.docstatus === 0 - && (!frm.doc.items[0][dimension['fieldname']])) { - frm.doc.items[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']]; - } - - if (frm.doc.accounts && frm.doc.accounts.length && frm.doc.docstatus === 0 - && (!frm.doc.items[0][dimension['fieldname']])) { - frm.doc.accounts[0][dimension['fieldname']] = erpnext.default_dimensions[frm.doc.company][dimension['document_type']]; - } - } }); }); }, company: function(frm) { - if(frm.doc.company && (Object.keys(erpnext.default_dimensions).length > 0)) { - erpnext.dimension_filters.forEach((dimension) => { - if (frappe.meta.has_field(doctype, dimension['fieldname'])) { - frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]); - } - }); + if(frm.doc.company && (Object.keys(default_dimensions || {}).length > 0) + && default_dimensions[frm.doc.company]) { + frm.trigger('update_dimension'); } }, + + update_dimension: function(frm) { + erpnext.dimension_filters.forEach((dimension) => { + if (frm.is_new()) { + if (frm.doc.company && Object.keys(default_dimensions || {}).length > 0 + && default_dimensions[frm.doc.company]) { + + if (frappe.meta.has_field(doctype, dimension['fieldname'])) { + frm.set_value(dimension['fieldname'], + default_dimensions[frm.doc.company][dimension['document_type']]); + } + + $.each(frm.doc.items || frm.doc.accounts || [], function(i, row) { + frappe.model.set_value(row.doctype, row.name, dimension['fieldname'], + default_dimensions[frm.doc.company][dimension['document_type']]) + }); + } + } + }); + } }); }); -erpnext.child_docs.forEach((doctype) => { +child_docs.forEach((doctype) => { frappe.ui.form.on(doctype, { items_add: function(frm, cdt, cdn) { erpnext.dimension_filters.forEach((dimension) => { @@ -77,14 +78,6 @@ erpnext.child_docs.forEach((doctype) => { }); }, - company: function(frm) { - if(frm.doc.company) { - erpnext.dimension_filters.forEach((dimension) => { - frm.set_value(dimension['fieldname'], erpnext.default_dimensions[frm.doc.company][dimension['document_type']]); - }); - } - }, - items_add: function(frm, cdt, cdn) { erpnext.dimension_filters.forEach((dimension) => { var row = frappe.get_doc(cdt, cdn); From 43806f3e68cccf648a5d149d5ad055395a2bf60f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 25 Mar 2020 16:52:07 +0530 Subject: [PATCH 111/137] fix: Place of supply validation in GSTR-1 report --- erpnext/regional/report/gstr_1/gstr_1.py | 27 ++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index 4f9cc7ff7a0..e9355f665e5 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -54,8 +54,8 @@ class Gstr1Report(object): return self.columns, self.data def get_data(self): - if self.filters.get("type_of_business") == "B2C Small": - self.get_b2cs_data() + if self.filters.get("type_of_business") in ("B2C Small", "B2C Large"): + self.get_b2c_data() else: for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): invoice_details = self.invoices.get(inv) @@ -69,7 +69,7 @@ class Gstr1Report(object): if taxable_value: self.data.append(row) - def get_b2cs_data(self): + def get_b2c_data(self): b2cs_output = {} for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): @@ -84,7 +84,10 @@ class Gstr1Report(object): "rate": "", "taxable_value": 0, "cess_amount": 0, - "type": "" + "type": "", + "invoice_number": invoice_details.get("invoice_number"), + "posting_date": invoice_details.get("posting_date"), + "invoice_value": invoice_details.get("base_grand_total"), }) row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin)) @@ -139,7 +142,7 @@ class Gstr1Report(object): where docstatus = 1 {where_conditions} order by posting_date desc """.format(select_columns=self.select_columns, doctype=self.doctype, - where_conditions=conditions), self.filters, as_dict=1) + where_conditions=conditions), self.filters, as_dict=1, debug=1) for d in invoice_data: self.invoices.setdefault(d.invoice_number, d) @@ -164,7 +167,7 @@ class Gstr1Report(object): frappe.throw(_("Please set B2C Limit in GST Settings.")) if self.filters.get("type_of_business") == "B2C Large": - conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2) + conditions += """ and ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'') and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit)) elif self.filters.get("type_of_business") == "B2C Small": @@ -581,6 +584,11 @@ def get_b2b_json(res, gstin): if not gst_in: continue for number, invoice in iteritems(res[gst_in]): + if not invoice[0]["place_of_supply"]: + frappe.throw(_("""{0} not entered in Invoice {1}. + Please update and try again""").format(frappe.bold("Place Of Supply"), + frappe.bold(invoice[0]['invoice_number']))) + inv_item = get_basic_invoice_detail(invoice[0]) inv_item["pos"] = "%02d" % int(invoice[0]["place_of_supply"].split('-')[0]) inv_item["rchrg"] = invoice[0]["reverse_charge"] @@ -606,6 +614,9 @@ def get_b2cs_json(data, gstin): out = [] for d in data: + if not d.get("place_of_supply"): + frappe.throw(_("""{0} not entered in some invoices. + Please update and try again""").format(frappe.bold("Place Of Supply"))) pos = d.get('place_of_supply').split('-')[0] tax_details = {} @@ -642,6 +653,10 @@ def get_b2cs_json(data, gstin): def get_b2cl_json(res, gstin): out = [] for pos in res: + if not pos: + frappe.throw(_("""{0} not entered in some invoices. + Please update and try again""").format(frappe.bold("Place Of Supply"))) + b2cl_item, inv = {"pos": "%02d" % int(pos.split('-')[0]), "inv": []}, [] for row in res[pos]: From 4f1a3876ec8302df49a0336903371297d420e6b3 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 25 Mar 2020 16:54:17 +0530 Subject: [PATCH 112/137] fix: Remove debug --- erpnext/regional/report/gstr_1/gstr_1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index e9355f665e5..a4d0bf59c11 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -142,7 +142,7 @@ class Gstr1Report(object): where docstatus = 1 {where_conditions} order by posting_date desc """.format(select_columns=self.select_columns, doctype=self.doctype, - where_conditions=conditions), self.filters, as_dict=1, debug=1) + where_conditions=conditions), self.filters, as_dict=1) for d in invoice_data: self.invoices.setdefault(d.invoice_number, d) From 750985dc23eba0ba9f70590d1c4cdb2a20c989e7 Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 26 Mar 2020 13:18:36 +0530 Subject: [PATCH 113/137] feat: auto set batch no on serial no selection (#20758) * feat: auto set batch no on serial no selection * fix: dialog not shown if set warehouse selected * fix: typo * fix: merge conflict * fix: callback no getting called after serial no selected * fix: callback no getting called after serial no selected * fix: available batch qty not fetched without set_warehouse selected * fix: item batch not synced with dialog batch table --- erpnext/public/js/controllers/transaction.js | 15 +- .../js/utils/serial_no_batch_selector.js | 144 +++++++++++------- erpnext/selling/sales_common.js | 9 +- erpnext/stock/doctype/serial_no/serial_no.py | 11 +- 4 files changed, 119 insertions(+), 60 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 146895097c5..ce27c6becce 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -4,7 +4,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ setup: function() { this._super(); - frappe.flags.hide_serial_batch_dialog = false; + frappe.flags.hide_serial_batch_dialog = true; frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); var has_margin_field = frappe.meta.has_field(cdt, 'margin_type'); @@ -506,6 +506,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }, () => me.frm.script_manager.trigger("price_list_rate", cdt, cdn), () => me.toggle_conversion_factor(item), + () => { + if (show_batch_dialog) + return frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"]) + .then((r) => { + if(r.message.has_batch_no || r.message.has_serial_no) { + frappe.flags.hide_serial_batch_dialog = false; + } + }); + }, () => { if(show_batch_dialog && !frappe.flags.hide_serial_batch_dialog) { var d = locals[cdt][cdn]; @@ -515,7 +524,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ erpnext.show_serial_batch_selector(me.frm, d, (item) => { me.frm.script_manager.trigger('qty', item.doctype, item.name); - }); + if (!me.frm.doc.set_warehouse) + me.frm.script_manager.trigger('warehouse', item.doctype, item.name); + }, undefined, !frappe.flags.hide_serial_batch_dialog); } }, () => me.conversion_factor(doc, cdt, cdn, true), diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js index 101ac9cd610..e78ab9fb690 100644 --- a/erpnext/public/js/utils/serial_no_batch_selector.js +++ b/erpnext/public/js/utils/serial_no_batch_selector.js @@ -5,14 +5,13 @@ erpnext.SerialNoBatchSelector = Class.extend({ this.show_dialog = show_dialog; // frm, item, warehouse_details, has_batch, oldest let d = this.item; - if (d && d.has_batch_no && (!d.batch_no || this.show_dialog)) { - this.has_batch = 1; - this.setup(); + this.has_batch = 0; this.has_serial_no = 0; + + if (d && d.has_batch_no && (!d.batch_no || this.show_dialog)) this.has_batch = 1; // !(this.show_dialog == false) ensures that show_dialog is implictly true, even when undefined - } else if(d && d.has_serial_no && !(this.show_dialog == false)) { - this.has_batch = 0; - this.setup(); - } + if(d && d.has_serial_no && !(this.show_dialog == false)) this.has_serial_no = 1; + + this.setup(); }, setup: function() { @@ -36,16 +35,16 @@ erpnext.SerialNoBatchSelector = Class.extend({ label: __('Item Code'), default: me.item_code }, - {fieldtype:'Column Break'}, { fieldname: 'warehouse', fieldtype:'Link', options: 'Warehouse', + reqd: me.has_batch && !me.has_serial_no ? 0 : 1, label: __(me.warehouse_details.type), - default: me.warehouse_details.name, + default: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '', onchange: function(e) { - if(me.has_batch) { + if(me.has_batch && !me.has_serial_no) { fields = fields.concat(me.get_batch_fields()); } else { fields = fields.concat(me.get_serial_no_fields()); @@ -74,15 +73,16 @@ erpnext.SerialNoBatchSelector = Class.extend({ { fieldname: 'qty', fieldtype:'Float', - read_only: me.has_batch, - label: __(me.has_batch ? 'Total Qty' : 'Qty'), + read_only: me.has_batch && !me.has_serial_no, + label: __(me.has_batch && !me.has_serial_no ? 'Total Qty' : 'Qty'), default: 0 }, { fieldname: 'auto_fetch_button', fieldtype:'Button', - hidden: me.has_batch, - label: __('Fetch based on FIFO'), + hidden: me.has_batch && !me.has_serial_no, + label: __('Auto Fetch'), + description: __('Fetch Serial Numbers based on FIFO'), click: () => { let qty = this.dialog.fields_dict.qty.get_value(); let numbers = frappe.call({ @@ -90,7 +90,7 @@ erpnext.SerialNoBatchSelector = Class.extend({ args: { qty: qty, item_code: me.item_code, - warehouse: me.warehouse_details.name, + warehouse: typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '', batch_no: me.item.batch_no || null } }); @@ -109,10 +109,12 @@ erpnext.SerialNoBatchSelector = Class.extend({ } ]; - if (this.has_batch) { + if (this.has_batch && !this.has_serial_no) { title = __("Select Batch Numbers"); fields = fields.concat(this.get_batch_fields()); } else { + // if only serial no OR + // if both batch_no & serial_no then only select serial_no and auto set batches nos title = __("Select Serial Numbers"); fields = fields.concat(this.get_serial_no_fields()); } @@ -122,25 +124,31 @@ erpnext.SerialNoBatchSelector = Class.extend({ fields: fields }); - if (this.item.serial_no) { - this.dialog.fields_dict.serial_no.set_value(this.item.serial_no); - } - this.dialog.set_primary_action(__('Insert'), function() { me.values = me.dialog.get_values(); if(me.validate()) { - me.set_items(); - me.dialog.hide(); + frappe.run_serially([ + () => me.update_batch_items(), + () => me.update_serial_no_item(), + () => me.update_batch_serial_no_items(), + () => { + refresh_field("items"); + if (me.callback) { + return me.callback(me.item); + } + }, + () => me.dialog.hide() + ]) } }); if(this.show_dialog) { let d = this.item; - if (d.has_serial_no && d.serial_no) { - this.dialog.set_value('serial_no', d.serial_no); + if (this.item.serial_no) { + this.dialog.fields_dict.serial_no.set_value(this.item.serial_no); } - - if (d.has_batch_no && d.batch_no) { + + if (this.has_batch && !this.has_serial_no && d.batch_no) { this.frm.doc.items.forEach(data => { if(data.item_code == d.item_code) { this.dialog.fields_dict.batches.df.data.push({ @@ -155,7 +163,7 @@ erpnext.SerialNoBatchSelector = Class.extend({ } } - if (this.has_batch) { + if (this.has_batch && !this.has_serial_no) { this.update_total_qty(); } @@ -174,7 +182,7 @@ erpnext.SerialNoBatchSelector = Class.extend({ frappe.throw(__("Please select a warehouse")); return false; } - if(this.has_batch) { + if(this.has_batch && !this.has_serial_no) { if(values.batches.length === 0 || !values.batches) { frappe.throw(__("Please select batches for batched item " + values.item_code)); @@ -193,34 +201,23 @@ erpnext.SerialNoBatchSelector = Class.extend({ } else { let serial_nos = values.serial_no || ''; if (!serial_nos || !serial_nos.replace(/\s/g, '').length) { - if (!this.show_dialog) { - frappe.throw(__("Please enter serial numbers for serialized item " - + values.item_code)); - return false; - } + frappe.throw(__("Please enter serial numbers for serialized item " + + values.item_code)); + return false; } return true; } }, - set_items: function() { - var me = this; - if(this.has_batch) { + update_batch_items() { + // clones an items if muliple batches are selected. + if(this.has_batch && !this.has_serial_no) { this.values.batches.map((batch, i) => { let batch_no = batch.batch_no; let row = ''; if (i !== 0 && !this.batch_exists(batch_no)) { - row = this.frm.add_child("items", { - 'item_code': this.item.item_code, - 'item_name': this.item.item_name, - 'price_list_rate': this.item.price_list_rate, - 'rate': this.item.rate, - 'qty': batch.selected_qty, - 'batch_no': batch_no, - 'actual_qty': this.item.actual_qty, - 'discount_percentage': this.item.discount_percentage - }); + row = this.frm.add_child("items", { ...this.item }); } else { row = this.frm.doc.items.find(i => i.batch_no === batch_no); } @@ -228,16 +225,59 @@ erpnext.SerialNoBatchSelector = Class.extend({ if (!row) { row = this.item; } - + // this ensures that qty & batch no is set this.map_row_values(row, batch, 'batch_no', 'selected_qty', this.values.warehouse); }); - } else { + } + }, + + update_serial_no_item() { + // just updates serial no for the item + if(this.has_serial_no && !this.has_batch) { this.map_row_values(this.item, this.values, 'serial_no', 'qty'); } + }, - refresh_field("items"); - this.callback && this.callback(this.item); + update_batch_serial_no_items() { + // if serial no selected is from different batches, adds new rows for each batch. + if(this.has_batch && this.has_serial_no) { + const selected_serial_nos = this.values.serial_no.split(/\n/g).filter(s => s); + + return frappe.db.get_list("Serial No", { + filters: { 'name': ["in", selected_serial_nos]}, + fields: ["batch_no", "name"] + }).then((data) => { + // data = [{batch_no: 'batch-1', name: "SR-001"}, + // {batch_no: 'batch-2', name: "SR-003"}, {batch_no: 'batch-2', name: "SR-004"}] + const batch_serial_map = data.reduce((acc, d) => { + if (!acc[d['batch_no']]) acc[d['batch_no']] = []; + acc[d['batch_no']].push(d['name']) + return acc + }, {}) + // batch_serial_map = { "batch-1": ['SR-001'], "batch-2": ["SR-003", "SR-004"]} + Object.keys(batch_serial_map).map((batch_no, i) => { + let row = ''; + const serial_no = batch_serial_map[batch_no]; + if (i == 0) { + row = this.item; + this.map_row_values(row, {qty: serial_no.length, batch_no: batch_no}, 'batch_no', + 'qty', this.values.warehouse); + } else if (!this.batch_exists(batch_no)) { + row = this.frm.add_child("items", { ...this.item }); + row.batch_no = batch_no; + } else { + row = this.frm.doc.items.find(i => i.batch_no === batch_no); + } + const values = { + 'qty': serial_no.length, + 'serial_no': serial_no.join('\n') + } + this.map_row_values(row, values, 'serial_no', + 'qty', this.values.warehouse); + }); + }) + } }, batch_exists: function(batch) { @@ -287,7 +327,7 @@ erpnext.SerialNoBatchSelector = Class.extend({ return { filters: { item_code: me.item_code, - warehouse: me.warehouse || me.warehouse_details.name + warehouse: me.warehouse || typeof me.warehouse_details.name == "string" ? me.warehouse_details.name : '' }, query: 'erpnext.controllers.queries.get_batch_no' }; @@ -447,7 +487,7 @@ erpnext.SerialNoBatchSelector = Class.extend({ { fieldname: 'serial_no', fieldtype: 'Small Text', - label: __(me.has_batch ? 'Selected Batch Numbers' : 'Selected Serial Numbers'), + label: __(me.has_batch && !me.has_serial_no ? 'Selected Batch Numbers' : 'Selected Serial Numbers'), onchange: function() { me.serial_list = this.get_value() .replace(/\n/g, ' ').match(/\S+/g) || []; diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 8278745a804..af100692c6f 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -413,15 +413,20 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ */ set_batch_number: function(cdt, cdn) { const doc = frappe.get_doc(cdt, cdn); - if (doc && doc.has_batch_no) { + if (doc && doc.has_batch_no && doc.warehouse) { this._set_batch_number(doc); } }, _set_batch_number: function(doc) { + let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)}; + if (doc.has_serial_no && doc.serial_no) { + args['serial_no'] = doc.serial_no + } + return frappe.call({ method: 'erpnext.stock.doctype.batch.batch.get_batch_no', - args: {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)}, + args: args, callback: function(r) { if(r.message) { frappe.model.set_value(doc.doctype, doc.name, 'batch_no', r.message); diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 31f84c9aaed..cc186f2dbe7 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -503,12 +503,15 @@ def get_delivery_note_serial_no(item_code, qty, delivery_note): return serial_nos @frappe.whitelist() -def auto_fetch_serial_number(qty, item_code, warehouse, batch_no=None): - serial_numbers = frappe.get_list("Serial No", filters={ +def auto_fetch_serial_number(qty, item_code, warehouse, batch_nos=None): + import json + filters = { "item_code": item_code, "warehouse": warehouse, - "batch_no": batch_no, "delivery_document_no": "", "sales_invoice": "" - }, limit=qty, order_by="creation") + } + if batch_nos: filters["batch_no"] = ["in", json.loads(batch_nos)] + + serial_numbers = frappe.get_list("Serial No", filters=filters, limit=qty, order_by="creation") return [item['name'] for item in serial_numbers] From b9f81d913b605228737d8f2c8e8ee63133fc9a9a Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 26 Mar 2020 13:20:27 +0530 Subject: [PATCH 114/137] fix: currency not fetched on quotation creation (#20998) --- erpnext/selling/doctype/customer/customer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 791a3e1536a..4fca05ba7ea 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -231,9 +231,11 @@ def make_quotation(source_name, target_doc=None): target_doc.run_method("set_other_charges") target_doc.run_method("calculate_taxes_and_totals") - price_list = frappe.get_value("Customer", source_name, "default_price_list") + price_list, currency = frappe.db.get_value("Customer", source_name, ['default_price_list', 'default_currency']) if price_list: target_doc.selling_price_list = price_list + if currency: + target_doc.currency = currency return target_doc From 01f80b239de1aa87e96d4753a90b8805c032e77a Mon Sep 17 00:00:00 2001 From: Saqib Date: Thu, 26 Mar 2020 13:23:06 +0530 Subject: [PATCH 115/137] fix: wrong calculation of depreciation eliminated for a period (#21032) --- .../asset_depreciations_and_balances.py | 213 +++++++++--------- 1 file changed, 112 insertions(+), 101 deletions(-) diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py index 0c99f1424cf..d7efbad240d 100644 --- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py +++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py @@ -4,126 +4,137 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import formatdate, getdate, flt, add_days +from frappe.utils import formatdate, flt, add_days + def execute(filters=None): filters.day_before_from_date = add_days(filters.from_date, -1) columns, data = get_columns(filters), get_data(filters) return columns, data - + + def get_data(filters): data = [] - + asset_categories = get_asset_categories(filters) assets = get_assets(filters) - asset_costs = get_asset_costs(assets, filters) - asset_depreciations = get_accumulated_depreciations(assets, filters) - + for asset_category in asset_categories: row = frappe._dict() - row.asset_category = asset_category - row.update(asset_costs.get(asset_category)) + # row.asset_category = asset_category + row.update(asset_category) + + row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase) - + flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset)) + + row.update(next(asset for asset in assets if asset["asset_category"] == asset_category.get("asset_category", ""))) + row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) + + flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated_during_the_period)) + + row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) - + flt(row.accumulated_depreciation_as_on_from_date)) + + row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) - + flt(row.accumulated_depreciation_as_on_to_date)) - row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase) - - flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset)) - - row.update(asset_depreciations.get(asset_category)) - row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) + - flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated)) - - row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) - - flt(row.accumulated_depreciation_as_on_from_date)) - - row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) - - flt(row.accumulated_depreciation_as_on_to_date)) - data.append(row) - + return data - + + def get_asset_categories(filters): - return frappe.db.sql_list(""" - select distinct asset_category from `tabAsset` - where docstatus=1 and company=%s and purchase_date <= %s - """, (filters.company, filters.to_date)) - + return frappe.db.sql(""" + SELECT asset_category, + ifnull(sum(case when purchase_date < %(from_date)s then + case when ifnull(disposal_date, 0) = 0 or disposal_date >= %(from_date)s then + gross_purchase_amount + else + 0 + end + else + 0 + end), 0) as cost_as_on_from_date, + ifnull(sum(case when purchase_date >= %(from_date)s then + gross_purchase_amount + else + 0 + end), 0) as cost_of_new_purchase, + ifnull(sum(case when ifnull(disposal_date, 0) != 0 + and disposal_date >= %(from_date)s + and disposal_date <= %(to_date)s then + case when status = "Sold" then + gross_purchase_amount + else + 0 + end + else + 0 + end), 0) as cost_of_sold_asset, + ifnull(sum(case when ifnull(disposal_date, 0) != 0 + and disposal_date >= %(from_date)s + and disposal_date <= %(to_date)s then + case when status = "Scrapped" then + gross_purchase_amount + else + 0 + end + else + 0 + end), 0) as cost_of_scrapped_asset + from `tabAsset` + where docstatus=1 and company=%(company)s and purchase_date <= %(to_date)s + group by asset_category + """, {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1) + def get_assets(filters): return frappe.db.sql(""" - select name, asset_category, purchase_date, gross_purchase_amount, disposal_date, status - from `tabAsset` - where docstatus=1 and company=%s and purchase_date <= %s""", - (filters.company, filters.to_date), as_dict=1) - -def get_asset_costs(assets, filters): - asset_costs = frappe._dict() - for d in assets: - asset_costs.setdefault(d.asset_category, frappe._dict({ - "cost_as_on_from_date": 0, - "cost_of_new_purchase": 0, - "cost_of_sold_asset": 0, - "cost_of_scrapped_asset": 0 - })) - - costs = asset_costs[d.asset_category] - - if getdate(d.purchase_date) < getdate(filters.from_date): - if not d.disposal_date or getdate(d.disposal_date) >= getdate(filters.from_date): - costs.cost_as_on_from_date += flt(d.gross_purchase_amount) - else: - costs.cost_of_new_purchase += flt(d.gross_purchase_amount) - - if d.disposal_date and getdate(d.disposal_date) >= getdate(filters.from_date) \ - and getdate(d.disposal_date) <= getdate(filters.to_date): - if d.status == "Sold": - costs.cost_of_sold_asset += flt(d.gross_purchase_amount) - elif d.status == "Scrapped": - costs.cost_of_scrapped_asset += flt(d.gross_purchase_amount) - - return asset_costs - -def get_accumulated_depreciations(assets, filters): - asset_depreciations = frappe._dict() - for d in assets: - asset = frappe.get_doc("Asset", d.name) - - if d.asset_category in asset_depreciations: - asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] += asset.opening_accumulated_depreciation - else: - asset_depreciations.setdefault(d.asset_category, frappe._dict({ - "accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation, - "depreciation_amount_during_the_period": 0, - "depreciation_eliminated_during_the_period": 0 - })) + SELECT results.asset_category, + sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date, + sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, + sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period + from (SELECT a.asset_category, + ifnull(sum(case when ds.schedule_date < %(from_date)s then + ds.depreciation_amount + else + 0 + end), 0) as accumulated_depreciation_as_on_from_date, + ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s + and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then + ds.depreciation_amount + else + 0 + end), 0) as depreciation_eliminated_during_the_period, + ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s + and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then + ds.depreciation_amount + else + 0 + end), 0) as depreciation_amount_during_the_period + from `tabAsset` a, `tabDepreciation Schedule` ds + where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent + group by a.asset_category + union + SELECT a.asset_category, + ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 + and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) + then + 0 + else + a.opening_accumulated_depreciation + end), 0) as accumulated_depreciation_as_on_from_date, + ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then + a.opening_accumulated_depreciation + else + 0 + end), 0) as depreciation_eliminated_during_the_period, + 0 as depreciation_amount_during_the_period + from `tabAsset` a + where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s + group by a.asset_category) as results + group by results.asset_category + """, {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1) - depr = asset_depreciations[d.asset_category] - if not asset.schedules: # if no schedule, - if asset.disposal_date: - # and disposal is NOT within the period, then opening accumulated depreciation not included - if getdate(asset.disposal_date) < getdate(filters.from_date) or getdate(asset.disposal_date) > getdate(filters.to_date): - asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] = 0 - - # if no schedule, and disposal is within period, accumulated dep is the amount eliminated - if getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date): - depr.depreciation_eliminated_during_the_period += asset.opening_accumulated_depreciation - - for schedule in asset.get("schedules"): - if getdate(schedule.schedule_date) < getdate(filters.from_date): - if not asset.disposal_date or getdate(asset.disposal_date) >= getdate(filters.from_date): - depr.accumulated_depreciation_as_on_from_date += flt(schedule.depreciation_amount) - elif getdate(schedule.schedule_date) <= getdate(filters.to_date): - if not asset.disposal_date: - depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount) - else: - if getdate(schedule.schedule_date) <= getdate(asset.disposal_date): - depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount) - - if asset.disposal_date and getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date): - if getdate(schedule.schedule_date) <= getdate(asset.disposal_date): - depr.depreciation_eliminated_during_the_period += flt(schedule.depreciation_amount) - - return asset_depreciations - def get_columns(filters): return [ { From 6b038bda0de5c7a81e942bec6602f244e02fd28b Mon Sep 17 00:00:00 2001 From: Marica Date: Thu, 26 Mar 2020 13:23:54 +0530 Subject: [PATCH 116/137] fix: Project field in Stock Entry Detail should be editable (#21000) --- .../doctype/stock_entry_detail/stock_entry_detail.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json index d86e68b7222..a848c80cf2c 100644 --- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json +++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "hash", "creation": "2013-03-29 18:22:12", "doctype": "DocType", @@ -479,8 +480,7 @@ "fieldname": "project", "fieldtype": "Link", "label": "Project", - "options": "Project", - "read_only": 1 + "options": "Project" }, { "fieldname": "po_detail", @@ -494,7 +494,8 @@ ], "idx": 1, "istable": 1, - "modified": "2019-08-20 14:01:02.319754", + "links": [], + "modified": "2020-03-19 12:34:09.836295", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry Detail", From 72430e91b267b5cc8fca9913862dba6ceace772d Mon Sep 17 00:00:00 2001 From: Raffael Meyer Date: Thu, 26 Mar 2020 08:55:14 +0100 Subject: [PATCH 117/137] fix: account groups (#21046) --- ..._kontenplan_SKR04_with_account_number.json | 387 ++++++++---------- 1 file changed, 177 insertions(+), 210 deletions(-) diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json index 275374a4b70..4ee12209caa 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/de_kontenplan_SKR04_with_account_number.json @@ -2417,29 +2417,26 @@ "Erl\u00f6se aus Verk\u00e4ufen Sachanlageverm\u00f6gen (bei Buchgewinn)": { "account_number": "4849" }, - "Erl\u00f6se aus Verk\u00e4ufen immaterieller VG (bei Buchgewinn) (Gruppe)": { - "is_group": 1, - "Erl\u00f6se aus Verk\u00e4ufen immaterieller VG (bei Buchgewinn)": { - "account_number": "4850" - }, - "Erl\u00f6se aus Verk\u00e4ufen Finanzanlagen (bei Buchgewinn)": { - "account_number": "4851" - }, - "Erl\u00f6se aus Verk\u00e4ufen Finanzanlagen (inl\u00e4ndische Kap.Ges., bei Buchgewinn)": { - "account_number": "4852" - }, - "Anlagenabg\u00e4nge Sachanlagen (Restbuchwert bei Buchvergewinn)": { - "account_number": "4855" - }, - "Anlagenabg\u00e4nge immaterielle VG (Restbuchwert bei Buchgewinn)": { - "account_number": "4856" - }, - "Anlagenabg\u00e4nge Finanzanlagen (Restbuchwert bei Buchgewinn)": { - "account_number": "4857" - }, - "Anlagenabg\u00e4nge Finanzanlagen (inl\u00e4ndische Kap.Ges., Restbuchwert bei Buchgewinn)": { - "account_number": "4858" - } + "Erl\u00f6se aus Verk\u00e4ufen immaterieller VG (bei Buchgewinn)": { + "account_number": "4850" + }, + "Erl\u00f6se aus Verk\u00e4ufen Finanzanlagen (bei Buchgewinn)": { + "account_number": "4851" + }, + "Erl\u00f6se aus Verk\u00e4ufen Finanzanlagen (inl\u00e4ndische Kap.Ges., bei Buchgewinn)": { + "account_number": "4852" + }, + "Anlagenabg\u00e4nge Sachanlagen (Restbuchwert bei Buchvergewinn)": { + "account_number": "4855" + }, + "Anlagenabg\u00e4nge immaterielle VG (Restbuchwert bei Buchgewinn)": { + "account_number": "4856" + }, + "Anlagenabg\u00e4nge Finanzanlagen (Restbuchwert bei Buchgewinn)": { + "account_number": "4857" + }, + "Anlagenabg\u00e4nge Finanzanlagen (inl\u00e4ndische Kap.Ges., Restbuchwert bei Buchgewinn)": { + "account_number": "4858" }, "Ertr\u00e4ge aus Zuschreibungen des Sachanlageverm\u00f6gens": { "account_number": "4910", @@ -2562,20 +2559,17 @@ "Entnahme von Gegenst\u00e4nden ohne USt": { "account_number": "4605" }, - "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens 7 % USt (Gruppe)": { - "is_group": 1, - "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens 7 % USt": { - "account_number": "4630" - }, - "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens ohne USt": { - "account_number": "4637" - }, - "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternnehmens ohne USt (Telefon-Nutzung)": { - "account_number": "4638" - }, - "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens ohne USt (Kfz-Nutzung)": { - "account_number": "4639" - } + "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens 7 % USt": { + "account_number": "4630" + }, + "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens ohne USt": { + "account_number": "4637" + }, + "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternnehmens ohne USt (Telefon-Nutzung)": { + "account_number": "4638" + }, + "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens ohne USt (Kfz-Nutzung)": { + "account_number": "4639" }, "Verwendung von Gegenst\u00e4nden f. Zwecke au\u00dferhalb des Unternehmens 19 % USt (Gruppe)": { "is_group": 1, @@ -2613,14 +2607,11 @@ "Unentgeltliche Zuwendung von Gegenst\u00e4nden ohne USt": { "account_number": "4689" }, - "Nicht steuerbare Ums\u00e4tze (Innenums\u00e4tze) (Gruppe)": { - "is_group": 1, - "Nicht steuerbare Ums\u00e4tze (Innenums\u00e4tze)": { - "account_number": "4690" - }, - "Umsatzsteuerverg\u00fctungen, z.B. nach \u00a7 24 UStG": { - "account_number": "4695" - } + "Nicht steuerbare Ums\u00e4tze (Innenums\u00e4tze)": { + "account_number": "4690" + }, + "Umsatzsteuerverg\u00fctungen, z.B. nach \u00a7 24 UStG": { + "account_number": "4695" }, "Au\u00dferordentliche Ertr\u00e4ge (Gruppe)": { "is_group": 1, @@ -2630,41 +2621,35 @@ "Au\u00dferordentliche Ertr\u00e4ge finanzwirksam": { "account_number": "7401" }, - "Au\u00dferordentliche Ertr\u00e4ge nicht finanzwirksam (Gruppe)": { - "is_group": 1, - "Au\u00dferordentliche Ertr\u00e4ge nicht finanzwirksam": { - "account_number": "7450" - }, - "Ertr\u00e4ge durch Verschmelzung und Umwandlung": { - "account_number": "7451" - }, - "Ertr\u00e4ge durch den Verkauf von bedeutenden Beteiligungen": { - "account_number": "7452" - }, - "Ert\u00e4ge durch den Verkauf von bedeutenden Grundst\u00fccken": { - "account_number": "7453" - }, - "Gewinn aus der Ver\u00e4u\u00dferung oder der Aufgabe von Gesch\u00e4ftsaktivit\u00e4ten nach Steuern": { - "account_number": "7454" - } + "Au\u00dferordentliche Ertr\u00e4ge nicht finanzwirksam": { + "account_number": "7450" }, - "Au\u00dferordentliche Ertr\u00e4ge aus der Anwendung von \u00dcbergangsvorschriften (Gruppe)": { - "is_group": 1, - "Au\u00dferordentliche Ertr\u00e4ge aus der Anwendung von \u00dcbergangsvorschriften": { - "account_number": "7460" - }, - "Au\u00dferordentliche Ertr\u00e4ge: Zuschreibung f. Sachanlageverm\u00f6gen": { - "account_number": "7461" - }, - "Au\u00dferordentliche Ertr\u00e4ge: Zuschreibung f. Finanzanlageverm\u00f6gen": { - "account_number": "7462" - }, - "Au\u00dferordentliche Ertr\u00e4ge: Wertpapiere im Umlaufverm\u00f6gen": { - "account_number": "7463" - }, - "Au\u00dferordentliche Ertr\u00e4ge: latente Steuern": { - "account_number": "7464" - } + "Ertr\u00e4ge durch Verschmelzung und Umwandlung": { + "account_number": "7451" + }, + "Ertr\u00e4ge durch den Verkauf von bedeutenden Beteiligungen": { + "account_number": "7452" + }, + "Ert\u00e4ge durch den Verkauf von bedeutenden Grundst\u00fccken": { + "account_number": "7453" + }, + "Gewinn aus der Ver\u00e4u\u00dferung oder der Aufgabe von Gesch\u00e4ftsaktivit\u00e4ten nach Steuern": { + "account_number": "7454" + }, + "Au\u00dferordentliche Ertr\u00e4ge aus der Anwendung von \u00dcbergangsvorschriften": { + "account_number": "7460" + }, + "Au\u00dferordentliche Ertr\u00e4ge: Zuschreibung f. Sachanlageverm\u00f6gen": { + "account_number": "7461" + }, + "Au\u00dferordentliche Ertr\u00e4ge: Zuschreibung f. Finanzanlageverm\u00f6gen": { + "account_number": "7462" + }, + "Au\u00dferordentliche Ertr\u00e4ge: Wertpapiere im Umlaufverm\u00f6gen": { + "account_number": "7463" + }, + "Au\u00dferordentliche Ertr\u00e4ge: latente Steuern": { + "account_number": "7464" } } }, @@ -2702,40 +2687,43 @@ }, "Erl\u00f6sschm\u00e4lerungen aus im Inland steuerpfl. EU-Lieferungen 16 % USt": { "account_number": "4729" + } + }, + "Gew\u00e4hrte Skonti (Gruppe)": { + "is_group": 1, + "Gew. Skonti": { + "account_number": "4730" }, - "Gew\u00e4hrte Skonti (Gruppe)": { - "is_group": 1, - "Gew. Skonti": { - "account_number": "4730" - }, - "Gew. Skonti 7 % USt": { - "account_number": "4731" - }, - "Gew. Skonti 19 % USt": { - "account_number": "4736" - }, - "Gew. Skonti aus Lieferungen von Mobilfunkger./Schaltkr., f. die der Leistungsempf. die Ust. schuldet": { - "account_number": "4738" - }, - "Gew. Skonti aus Leistungen, f. die der Leistungsempf. die Umsatzsteuer nach \u00a7 13b UStG schuldet": { - "account_number": "4741" - }, - "Gew. Skonti aus Erl\u00f6sen aus im anderen EU-Land steuerpfl. Leistungen, f. die der Leistungsempf. die Ust. schuldet": { - "account_number": "4742" - }, - "Gew. Skonti aus steuerfreien innergem. Lieferungen \u00a7 4 Nr. 1b UStG": { - "account_number": "4743" - }, - "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen": { - "account_number": "4745" - }, - "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 7% USt": { - "account_number": "4746" - }, - "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 19% USt": { - "account_number": "4748" - } + "Gew. Skonti 7 % USt": { + "account_number": "4731" }, + "Gew. Skonti 19 % USt": { + "account_number": "4736" + }, + "Gew. Skonti aus Lieferungen von Mobilfunkger./Schaltkr., f. die der Leistungsempf. die Ust. schuldet": { + "account_number": "4738" + }, + "Gew. Skonti aus Leistungen, f. die der Leistungsempf. die Umsatzsteuer nach \u00a7 13b UStG schuldet": { + "account_number": "4741" + }, + "Gew. Skonti aus Erl\u00f6sen aus im anderen EU-Land steuerpfl. Leistungen, f. die der Leistungsempf. die Ust. schuldet": { + "account_number": "4742" + }, + "Gew. Skonti aus steuerfreien innergem. Lieferungen \u00a7 4 Nr. 1b UStG": { + "account_number": "4743" + }, + "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen": { + "account_number": "4745" + }, + "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 7% USt": { + "account_number": "4746" + }, + "Gew. Skonti aus im Inland steuerpfl. EU-Lieferungen 19% USt": { + "account_number": "4748" + } + }, + "Gew\u00e4hrte Boni (Gruppe)": { + "is_group": 1, "Gew\u00e4hrte Boni 7 % USt": { "account_number": "4750" }, @@ -2848,103 +2836,79 @@ "account_number": "6398" } }, - "Versicherungen (Gruppe)": { - "is_group": 1, - "Versicherungen": { - "account_number": "6400" - }, - "Versicherungen f. Geb\u00e4ude, die zum Betriebsverm\u00f6gen geh\u00f6ren": { - "account_number": "6405" - }, - "Netto-Pr\u00e4mie f. R\u00fcckdeckung k\u00fcnftiger Versorgungsleistungen": { - "account_number": "6410" - }, - "Beitr\u00e4ge": { - "account_number": "6420" - }, - "Sonstige Abgaben": { - "account_number": "6430" - }, - "Steuerlich abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": { - "account_number": "6436" - }, - "Steuerlich nicht abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": { - "account_number": "6437" - }, - "Ausgleichsabgabe i. S. d. Schwerbehindertengesetzes": { - "account_number": "6440" - }, - "Reparaturen und Instandhaltung von Bauten": { - "account_number": "6450" - }, - "Reparaturen und Instandhaltung von technischenAnlagen und Maschinen": { - "account_number": "6460" - }, - "Reparaturen und Instandhaltung von anderen Anlagen und Betriebs- und Gesch\u00e4ftsausstattung": { - "account_number": "6470" - }, - "Zuf\u00fchrung zu Aufwandsr\u00fcckstellungen": { - "account_number": "6475" - }, - "Reparaturen und Instandhaltung von anderen Anlagen": { - "account_number": "6485" - }, - "Sonstige Reparaturen und Instandhaltungen": { - "account_number": "6490" - }, - "Wartungskosten f. Hard- und Software": { - "account_number": "6495" - }, - "Mietleasing (bewegliche Wirtschaftsg\u00fcter)": { - "account_number": "6498" - } + "Versicherungen": { + "account_number": "6400" + }, + "Versicherungen f. Geb\u00e4ude, die zum Betriebsverm\u00f6gen geh\u00f6ren": { + "account_number": "6405" + }, + "Netto-Pr\u00e4mie f. R\u00fcckdeckung k\u00fcnftiger Versorgungsleistungen": { + "account_number": "6410" + }, + "Beitr\u00e4ge": { + "account_number": "6420" + }, + "Sonstige Abgaben": { + "account_number": "6430" + }, + "Steuerlich abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": { + "account_number": "6436" + }, + "Steuerlich nicht abzugsf\u00e4hige Versp\u00e4tungszuschl\u00e4ge und Zwangsgelder": { + "account_number": "6437" + }, + "Ausgleichsabgabe i. S. d. Schwerbehindertengesetzes": { + "account_number": "6440" + }, + "Reparaturen und Instandhaltung von Bauten": { + "account_number": "6450" + }, + "Reparaturen und Instandhaltung von technischenAnlagen und Maschinen": { + "account_number": "6460" + }, + "Reparaturen und Instandhaltung von anderen Anlagen und Betriebs- und Gesch\u00e4ftsausstattung": { + "account_number": "6470" + }, + "Zuf\u00fchrung zu Aufwandsr\u00fcckstellungen": { + "account_number": "6475" + }, + "Reparaturen und Instandhaltung von anderen Anlagen": { + "account_number": "6485" + }, + "Sonstige Reparaturen und Instandhaltungen": { + "account_number": "6490" + }, + "Wartungskosten f. Hard- und Software": { + "account_number": "6495" + }, + "Mietleasing (bewegliche Wirtschaftsg\u00fcter)": { + "account_number": "6498" }, "Fahrzeugkosten (Gruppe)": { "is_group": 1, "Fahrzeugkosten": { "account_number": "6500" }, - "Kfz-Versicherungen (Gruppe)": { - "is_group": 1, - "Kfz-Versicherungen": { - "account_number": "6520" - } + "Kfz-Versicherungen": { + "account_number": "6520" }, - "Laufende Kfz-Betriebskosten (Gruppe)": { - "is_group": 1, - "Laufende Kfz-Betriebskosten": { - "account_number": "6530" - } + "Laufende Kfz-Betriebskosten": { + "account_number": "6530" }, - "Kfz-Reparaturen (Gruppe)": { - "is_group": 1, - "Kfz-Reparaturen": { - "account_number": "6540" - } + "Kfz-Reparaturen": { + "account_number": "6540" }, - "Garagenmiete (Gruppe)": { - "is_group": 1, - "Garagenmiete": { - "account_number": "6550" - } + "Garagenmiete": { + "account_number": "6550" }, - "Mietleasing Kfz (Gruppe)": { - "is_group": 1, - "Mietleasing Kfz": { - "account_number": "6560" - } + "Mietleasing Kfz": { + "account_number": "6560" }, - "Sonstige Kfz-Kosten (Gruppe)": { - "is_group": 1, - "Sonstige Kfz-Kosten": { - "account_number": "6570" - } + "Sonstige Kfz-Kosten": { + "account_number": "6570" }, - "Mautgeb\u00fchren (Gruppe)": { - "is_group": 1, - "Mautgeb\u00fchren": { - "account_number": "6580" - } + "Mautgeb\u00fchren": { + "account_number": "6580" }, "Kfz-Kosten f. betrieblich genutzte zum Privatverm\u00f6gen geh\u00f6rende Kraftfahrzeuge": { "account_number": "6590" @@ -3006,20 +2970,23 @@ "Nicht abzugsf\u00e4hige Betriebsausgaben aus Werbe- und Repr\u00e4sentationskosten": { "account_number": "6645" }, - "Reisekosten Arbeitnehmer": { - "account_number": "6650" - }, - "Reisekosten Arbeitnehmer \u00dcbernachtungsaufwand": { - "account_number": "6660" - }, - "Reisekosten Arbeitnehmer Fahrtkosten": { - "account_number": "6663" - }, - "Reisekosten Arbeitnehmer Verpflegungsmehraufwand": { - "account_number": "6664" - }, - "Kilometergelderstattung Arbeitnehmer": { - "account_number": "6668" + "Reisekosten Arbeitnehmer (Gruppe)": { + "is_group": 1, + "Reisekosten Arbeitnehmer": { + "account_number": "6650" + }, + "Reisekosten Arbeitnehmer \u00dcbernachtungsaufwand": { + "account_number": "6660" + }, + "Reisekosten Arbeitnehmer Fahrtkosten": { + "account_number": "6663" + }, + "Reisekosten Arbeitnehmer Verpflegungsmehraufwand": { + "account_number": "6664" + }, + "Kilometergelderstattung Arbeitnehmer": { + "account_number": "6668" + } }, "Reisekosten Unternehmer (Gruppe)": { "is_group": 1, From 3c378aaac743ded787365019d426970bfbb0cc46 Mon Sep 17 00:00:00 2001 From: Marica Date: Thu, 26 Mar 2020 13:28:42 +0530 Subject: [PATCH 118/137] fix: Make shelf life mandatory in Batched Item if it has expiry date (#21045) --- erpnext/stock/doctype/batch/batch.py | 7 +++++-- erpnext/stock/doctype/item/item.json | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py index 8ae978eaf05..9b7249e66b9 100644 --- a/erpnext/stock/doctype/batch/batch.py +++ b/erpnext/stock/doctype/batch/batch.py @@ -122,8 +122,11 @@ class Batch(Document): self.expiry_date = add_days(self.manufacturing_date, shelf_life_in_days) if has_expiry_date and not self.expiry_date: - frappe.msgprint(_('Expiry date is mandatory for selected item.')) - frappe.throw(_("Set item's shelf life in days, to set expiry based on manufacturing date plus shelf-life.")) + frappe.throw(msg=_("Please set {0} for Batched Item {1}, which is used to set {2} on Submit.") \ + .format(frappe.bold("Shelf Life in Days"), + frappe.utils.get_link_to_form("Item", self.item), + frappe.bold("Batch Expiry Date")), + title=_("Expiry Date Mandatory")) def get_name_from_naming_series(self): """ diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 3503e7cc1c5..aa6b2fedd7c 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -343,7 +343,8 @@ { "fieldname": "shelf_life_in_days", "fieldtype": "Int", - "label": "Shelf Life In Days" + "label": "Shelf Life In Days", + "mandatory_depends_on": "eval:doc.has_batch_no && doc.has_expiry_date" }, { "default": "2099-12-31", @@ -1045,7 +1046,7 @@ "image_field": "image", "links": [], "max_attachments": 1, - "modified": "2020-01-02 19:13:59.295963", + "modified": "2020-03-24 16:14:36.950677", "modified_by": "Administrator", "module": "Stock", "name": "Item", From 8a5587749b5f8c73bc72831d4e223911791ed426 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Thu, 26 Mar 2020 13:29:36 +0530 Subject: [PATCH 119/137] fix: Added hidden GL column in general ledger (#21022) Co-authored-by: Nabin Hait --- erpnext/accounts/report/general_ledger/general_ledger.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index f45911f90e5..6c9dec90f8c 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -131,7 +131,7 @@ def get_gl_entries(filters): gl_entries = frappe.db.sql( """ select - posting_date, account, party_type, party, + name as gl_entry, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center, project, against_voucher_type, against_voucher, account_currency, remarks, against, is_opening {select_fields} @@ -362,6 +362,12 @@ def get_columns(filters): currency = get_company_currency(company) columns = [ + { + "fieldname": "gl_entry", + "fieldtype": "Link", + "options": "GL Entry", + "hidden": 1 + }, { "label": _("Posting Date"), "fieldname": "posting_date", From ff49a2f0b61483b0614018b902b9b206ffdaa623 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 26 Mar 2020 13:36:21 +0530 Subject: [PATCH 120/137] fix: Ignored user permission for parent_company and existing_company field in Company (#21010) --- erpnext/setup/doctype/company/company.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 5ce51a6e8d9..3eb8949a5fa 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -157,6 +157,7 @@ { "fieldname": "parent_company", "fieldtype": "Link", + "ignore_user_permissions": 1, "in_list_view": 1, "label": "Parent Company", "options": "Company" @@ -277,6 +278,7 @@ "depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"", "fieldname": "existing_company", "fieldtype": "Link", + "ignore_user_permissions": 1, "label": "Existing Company ", "no_copy": 1, "options": "Company" @@ -728,7 +730,7 @@ "image_field": "company_logo", "is_tree": 1, "links": [], - "modified": "2020-03-18 18:26:03.145312", + "modified": "2020-03-22 18:26:03.145312", "modified_by": "Administrator", "module": "Setup", "name": "Company", From 27f0d13bdd4490429453de3024451f466bc3227d Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Fri, 6 Mar 2020 20:55:02 +0530 Subject: [PATCH 121/137] feat: add status filter in issue web form --- erpnext/support/web_form/issues/issues.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/support/web_form/issues/issues.json b/erpnext/support/web_form/issues/issues.json index 652114f7382..0f15e4737fd 100644 --- a/erpnext/support/web_form/issues/issues.json +++ b/erpnext/support/web_form/issues/issues.json @@ -18,7 +18,7 @@ "is_standard": 1, "login_required": 1, "max_attachment_size": 0, - "modified": "2019-06-27 22:58:49.609672", + "modified": "2020-03-06 05:24:05.749664", "modified_by": "Administrator", "module": "Support", "name": "issues", @@ -58,7 +58,7 @@ "options": "Open\nReplied\nHold\nClosed", "read_only": 1, "reqd": 0, - "show_in_filter": 0 + "show_in_filter": 1 }, { "allow_read_on_all_link_options": 0, From d90f6581633df6e589c4dbb6d39a63b089f5f5ed Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 27 Mar 2020 12:54:01 +0530 Subject: [PATCH 122/137] fix: item not showing in popup while making batch --- erpnext/public/js/controllers/transaction.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 146895097c5..6c580d046f5 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -165,6 +165,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ return (doc.rule_applied) ? "green" : "red"; }); } + + let batch_no_field = this.frm.get_docfield("items", "batch_no"); + if (batch_no_field) { + batch_no_field.get_route_options_for_new_doc = function(row) { + return { + "item": row.doc.item_code + } + }; + } + }, onload: function() { var me = this; From b03d1327a57a9d0afbdf957bcb4dc98caf4f5127 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 27 Mar 2020 19:24:17 +0530 Subject: [PATCH 123/137] fix: Add item defaults based on global settings only if default company and warehouse is mentioned --- erpnext/stock/doctype/item/item.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index cb0eb406df6..24896f09da1 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -741,14 +741,12 @@ class Item(WebsiteGenerator): defaults = frappe.defaults.get_defaults() or {} # To check default warehouse is belong to the default company - if defaults.get("default_warehouse") and frappe.db.exists("Warehouse", + if defaults.get("default_warehouse") and defaults.company and frappe.db.exists("Warehouse", {'name': defaults.default_warehouse, 'company': defaults.company}): - warehouse = defaults.default_warehouse - - self.append("item_defaults", { - "company": defaults.get("company"), - "default_warehouse": warehouse - }) + self.append("item_defaults", { + "company": defaults.get("company"), + "default_warehouse": defaults.default_warehouse + }) def update_variants(self): if self.flags.dont_update_variants or \ From 2313d2d80a54d1a71141d677a7efb04a747acab4 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 27 Mar 2020 19:15:59 +0530 Subject: [PATCH 124/137] fix: total currency formatting --- .../accounts_receivable.html | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html index 791f3f8008b..bb0d0a132a5 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html @@ -218,15 +218,15 @@

{%= __("Total") %} - {%= format_currency(data[i]["invoiced"], data[i]["currency"] ) %} - {%= format_currency(data[i]["paid"], data[i]["currency"]) %}{%= format_currency(data[i]["credit_note"], data[i]["currency"]) %} {%= format_currency(data[i]["credit_note"], data[0]["currency"]) %} - {%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}{%= data[i]["future_ref"] %}{%= format_currency(data[i]["future_amount"], data[i]["currency"]) %}{%= format_currency(data[i]["remaining_balance"], data[i]["currency"]) %}{%= format_currency(data[i]["future_amount"], data[0]["currency"]) %}{%= format_currency(data[i]["remaining_balance"], data[0]["currency"]) %}{%= __("Total") %}{%= format_currency(data[i]["invoiced"], data[i]["currency"]) %}{%= format_currency(data[i]["paid"], data[i]["currency"]) %}{%= format_currency(data[i]["credit_note"], data[i]["currency"]) %}{%= format_currency(data[i]["outstanding"], data[i]["currency"]) %}{%= format_currency(data[i]["invoiced"], data[0]["currency"]) %}{%= format_currency(data[i]["paid"], data[0]["currency"]) %}{%= format_currency(data[i]["credit_note"], data[0]["currency"]) %}{%= format_currency(data[i]["outstanding"], data[0]["currency"]) %}