From df1eae8981ac76211c4d912fc26dc152d2d76adf Mon Sep 17 00:00:00 2001 From: Alchez Date: Fri, 13 Jul 2018 12:50:04 +0530 Subject: [PATCH] Merge the Land Unit doctype with the Location doctype (#14613) * Merge Land Unit with the Location doctype * Fix patch * [minor] modification to Location structure - Create a group node "All Land Units" and place all the land units under it - Remove "Linked Analysis" from location --- .../doctype/crop_cycle/crop_cycle.js | 10 +- .../doctype/crop_cycle/crop_cycle.json | 14 +- .../doctype/crop_cycle/crop_cycle.py | 8 +- .../doctype/crop_cycle/test_crop_cycle.py | 58 +- .../doctype/land_unit/land_unit.js | 30 - .../doctype/land_unit/land_unit.json | 691 ------------- .../doctype/land_unit/land_unit.py | 182 ---- .../doctype/land_unit/land_unit_tree.js | 30 - .../doctype/land_unit/test_land_unit.js | 23 - .../doctype/land_unit/test_land_unit.py | 26 - .../__init__.py | 0 .../linked_location.json} | 12 +- .../linked_location.py} | 4 +- .../doctype/linked_location}/__init__.py | 0 .../linked_location/linked_location.json | 74 ++ .../linked_location/linked_location.py | 10 + erpnext/assets/doctype/location/location.js | 20 +- erpnext/assets/doctype/location/location.json | 964 +++++++++++++----- erpnext/assets/doctype/location/location.py | 193 +++- .../assets/doctype/location/location_tree.js | 10 +- .../assets/doctype/location/test_location.js | 4 +- .../assets/doctype/location/test_location.py | 25 +- .../doctype/location}/test_records.json | 30 +- erpnext/config/agriculture.py | 2 +- erpnext/config/desktop.py | 8 +- erpnext/domains/agriculture.py | 2 +- erpnext/patches.txt | 3 +- .../v11_0/merge_land_unit_with_location.py | 60 ++ erpnext/tests/server/agriculture.txt | 1 - 29 files changed, 1141 insertions(+), 1353 deletions(-) delete mode 100644 erpnext/agriculture/doctype/land_unit/land_unit.js delete mode 100644 erpnext/agriculture/doctype/land_unit/land_unit.json delete mode 100644 erpnext/agriculture/doctype/land_unit/land_unit.py delete mode 100644 erpnext/agriculture/doctype/land_unit/land_unit_tree.js delete mode 100644 erpnext/agriculture/doctype/land_unit/test_land_unit.js delete mode 100644 erpnext/agriculture/doctype/land_unit/test_land_unit.py rename erpnext/agriculture/doctype/{land_unit => linked_location}/__init__.py (100%) rename erpnext/agriculture/doctype/{linked_land_unit/linked_land_unit.json => linked_location/linked_location.json} (87%) rename erpnext/agriculture/doctype/{linked_land_unit/linked_land_unit.py => linked_location/linked_location.py} (65%) rename erpnext/{agriculture/doctype/linked_land_unit => assets/doctype/linked_location}/__init__.py (100%) create mode 100644 erpnext/assets/doctype/linked_location/linked_location.json create mode 100644 erpnext/assets/doctype/linked_location/linked_location.py rename erpnext/{agriculture/doctype/land_unit => assets/doctype/location}/test_records.json (74%) create mode 100644 erpnext/patches/v11_0/merge_land_unit_with_location.py diff --git a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.js b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.js index ae28bb7044..94392e7261 100644 --- a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.js +++ b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.js @@ -10,7 +10,7 @@ frappe.ui.form.on('Crop Cycle', { let analysis_doctypes = ['Soil Texture', 'Plant Analysis', 'Soil Analysis']; let analysis_doctypes_docs = ['soil_texture', 'plant_analysis', 'soil_analysis']; let obj_to_append = {soil_analysis: [], soil_texture: [], plant_analysis: []}; - output['Land Unit'].forEach( (land_doc) => { + output['Location'].forEach( (land_doc) => { analysis_doctypes.forEach( (doctype) => { output[doctype].forEach( (analysis_doc) => { let point_to_be_tested = JSON.parse(analysis_doc.location).features[0].geometry.coordinates; @@ -31,18 +31,18 @@ frappe.ui.form.on('Crop Cycle', { function is_in_land_unit(point, vs) { // ray-casting algorithm based on // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html - + var x = point[0], y = point[1]; - + var inside = false; for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) { var xi = vs[i][0], yi = vs[i][1]; var xj = vs[j][0], yj = vs[j][1]; - + var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) inside = !inside; } - + return inside; }; diff --git a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.json b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.json index 0263b65ecb..18a3b8c6bb 100644 --- a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.json +++ b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.json @@ -43,7 +43,7 @@ "search_index": 0, "set_only_once": 0, "translatable": 0, - "unique": 0 + "unique": 1 }, { "allow_bulk_edit": 0, @@ -95,7 +95,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Linked Land Unit", + "label": "Linked Location", "length": 0, "no_copy": 0, "permlevel": 0, @@ -118,8 +118,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "description": "A link to all the Land Units in which the Crop is growing", - "fieldname": "linked_land_unit", + "description": "A link to all the Locations in which the Crop is growing", + "fieldname": "linked_location", "fieldtype": "Table", "hidden": 0, "ignore_user_permissions": 0, @@ -128,10 +128,10 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Linked Land Unit", + "label": "Linked Location", "length": 0, "no_copy": 0, - "options": "Linked Land Unit", + "options": "Linked Location", "permlevel": 0, "precision": "", "print_hide": 0, @@ -844,7 +844,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-06-05 03:24:09.054864", + "modified": "2018-06-20 04:41:36.148829", "modified_by": "Administrator", "module": "Agriculture", "name": "Crop Cycle", diff --git a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py index e090706200..bb9045ca81 100644 --- a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py +++ b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py @@ -81,10 +81,10 @@ class CropCycle(Document): for doctype in linked_doctypes: output[doctype] = frappe.get_all(doctype, fields=required_fields) - output['Land Unit'] = [] + output['Location'] = [] - for land in self.linked_land_unit: - output['Land Unit'].append(frappe.get_doc('Land Unit', land.land_unit)) + for location in self.linked_location: + output['Location'].append(frappe.get_doc('Location', location.location)) frappe.publish_realtime("List of Linked Docs", output, user=frappe.session.user) @@ -105,7 +105,7 @@ def get_geometry_type(doc): return ast.literal_eval(doc.location).get('features')[0].get('geometry').get('type') -def is_in_land_unit(point, vs): +def is_in_location(point, vs): x, y = point inside = False diff --git a/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py b/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py index 136858b89f..5510d5ac02 100644 --- a/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py +++ b/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py @@ -3,66 +3,72 @@ # See license.txt from __future__ import unicode_literals -import frappe import unittest -test_dependencies = ["Crop", "Fertilizer", "Land Unit", "Disease"] +import frappe +from frappe.utils import datetime + +test_dependencies = ["Crop", "Fertilizer", "Location", "Disease"] + class TestCropCycle(unittest.TestCase): def test_crop_cycle_creation(self): cycle = frappe.get_doc('Crop Cycle', 'Basil from seed 2017') - self.assertEqual(frappe.db.exists('Crop Cycle', 'Basil from seed 2017'), 'Basil from seed 2017') + self.assertTrue(frappe.db.exists('Crop Cycle', 'Basil from seed 2017')) - # check if the tasks were created + # check if the tasks were created self.assertEqual(check_task_creation(), True) self.assertEqual(check_project_creation(), True) + def check_task_creation(): all_task_dict = { "Survey and find the aphid locations": { - "exp_start_date": frappe.utils.datetime.date(2017,11,21), - "exp_end_date": frappe.utils.datetime.date(2017,11,22) + "exp_start_date": datetime.date(2017, 11, 21), + "exp_end_date": datetime.date(2017, 11, 22) }, "Apply Pesticides": { - "exp_start_date": frappe.utils.datetime.date(2017,11,23), - "exp_end_date": frappe.utils.datetime.date(2017,11,23) + "exp_start_date": datetime.date(2017, 11, 23), + "exp_end_date": datetime.date(2017, 11, 23) }, "Plough the field": { - "exp_start_date": frappe.utils.datetime.date(2017,11,11), - "exp_end_date": frappe.utils.datetime.date(2017,11,11) + "exp_start_date": datetime.date(2017, 11, 11), + "exp_end_date": datetime.date(2017, 11, 11) }, "Plant the seeds": { - "exp_start_date": frappe.utils.datetime.date(2017,11,12), - "exp_end_date": frappe.utils.datetime.date(2017,11,13) + "exp_start_date": datetime.date(2017, 11, 12), + "exp_end_date": datetime.date(2017, 11, 13) }, "Water the field": { - "exp_start_date": frappe.utils.datetime.date(2017,11,14), - "exp_end_date": frappe.utils.datetime.date(2017,11,14) + "exp_start_date": datetime.date(2017, 11, 14), + "exp_end_date": datetime.date(2017, 11, 14) }, "First harvest": { - "exp_start_date": frappe.utils.datetime.date(2017,11,18), - "exp_end_date": frappe.utils.datetime.date(2017,11,18) + "exp_start_date": datetime.date(2017, 11, 18), + "exp_end_date": datetime.date(2017, 11, 18) }, "Add the fertilizer": { - "exp_start_date": frappe.utils.datetime.date(2017,11,20), - "exp_end_date": frappe.utils.datetime.date(2017,11,22) + "exp_start_date": datetime.date(2017, 11, 20), + "exp_end_date": datetime.date(2017, 11, 22) }, - "Final cut":{ - "exp_start_date": frappe.utils.datetime.date(2017,11,25), - "exp_end_date": frappe.utils.datetime.date(2017,11,25) + "Final cut": { + "exp_start_date": datetime.date(2017, 11, 25), + "exp_end_date": datetime.date(2017, 11, 25) } } + all_tasks = frappe.get_all('Task') + for task in all_tasks: sample_task = frappe.get_doc('Task', task.name) + if sample_task.subject in list(all_task_dict): if sample_task.exp_start_date != all_task_dict[sample_task.subject]['exp_start_date'] or sample_task.exp_end_date != all_task_dict[sample_task.subject]['exp_end_date']: return False all_task_dict.pop(sample_task.subject) - if all_task_dict != {}: - return False - return True + + return True if not all_task_dict else False + def check_project_creation(): - if frappe.db.exists('Project', 'Basil from seed 2017'): return True - else: return False \ No newline at end of file + return True if frappe.db.exists('Project', 'Basil from seed 2017') else False diff --git a/erpnext/agriculture/doctype/land_unit/land_unit.js b/erpnext/agriculture/doctype/land_unit/land_unit.js deleted file mode 100644 index 3bf1434bca..0000000000 --- a/erpnext/agriculture/doctype/land_unit/land_unit.js +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -// Code for finding the area of editable features drawn on the geolocation control - - - -frappe.ui.form.on('Land Unit', { - setup: function(frm) { - frm.add_fetch("parent_land_unit", "latitude", "latitude"); - frm.add_fetch("parent_land_unit", "longitude", "longitude"); - frm.set_query("parent_land_unit", function() { - return { - "filters": { - "is_group": 1 - } - }; - }); - }, - - onload_post_render(frm){ - if(!frm.doc.location && frm.doc.latitude && frm.doc.longitude) { - frm.fields_dict.location.map.setView([frm.doc.latitude, frm.doc.longitude],13); - } - else { - frm.doc.latitude = frm.fields_dict.location.map.getCenter()['lat']; - frm.doc.longitude = frm.fields_dict.location.map.getCenter()['lng']; - } - }, -}); diff --git a/erpnext/agriculture/doctype/land_unit/land_unit.json b/erpnext/agriculture/doctype/land_unit/land_unit.json deleted file mode 100644 index 94d350f597..0000000000 --- a/erpnext/agriculture/doctype/land_unit/land_unit.json +++ /dev/null @@ -1,691 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:land_unit_name", - "beta": 0, - "creation": "2017-10-21 05:35:34.508529", - "custom": 0, - "description": "Land Unit describing various land assets", - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "land_unit_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": "Land Unit Name", - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "parent_land_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 Land Unit", - "length": 0, - "no_copy": 0, - "options": "Land 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, - "unique": 0 - }, - { - "allow_bulk_edit": 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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Check if it is a hydroponic unit", - "fieldname": "is_container", - "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 Container", - "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "default": "", - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "tree_details", - "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, - "label": "Tree 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, - "unique": 0 - }, - { - "allow_bulk_edit": 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, - "unique": 0 - }, - { - "allow_bulk_edit": 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, - "unique": 0 - }, - { - "allow_bulk_edit": 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": "Land 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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "land_unit_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": "Land Unit 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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "latitude", - "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": "Latitude", - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "longitude", - "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": "Longitude", - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "latlong", - "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, - "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "area", - "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": "Area", - "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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 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, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "location", - "fieldtype": "Geolocation", - "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": "Location", - "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "section_break_17", - "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": "Linked Analysis", - "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "linked_soil_texture", - "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": "Linked Soil Texture", - "length": 0, - "no_copy": 0, - "options": "Linked Soil Texture", - "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "linked_soil_analysis", - "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": "Linked Soil Analysis", - "length": 0, - "no_copy": 0, - "options": "Linked Soil Analysis", - "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "linked_plant_analysis", - "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": "Linked Plant Analysis", - "length": 0, - "no_copy": 0, - "options": "Linked Plant Analysis", - "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 - } - ], - "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-12-14 18:16:15.124188", - "modified_by": "Administrator", - "module": "Agriculture", - "name": "Land Unit", - "name_case": "Title Case", - "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": "Agriculture Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 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": "Agriculture User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/agriculture/doctype/land_unit/land_unit.py b/erpnext/agriculture/doctype/land_unit/land_unit.py deleted file mode 100644 index 269bbceeab..0000000000 --- a/erpnext/agriculture/doctype/land_unit/land_unit.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals -import frappe -import json -import math - -from frappe import _ - -from frappe.utils.nestedset import NestedSet -from frappe.utils import flt -# from frappe.model.document import Document - -RADIUS = 6378137 -FLATTENING_DENOM = 298.257223563 -FLATTENING = 1/FLATTENING_DENOM -POLAR_RADIUS = RADIUS*(1-FLATTENING) - -class LandUnit(NestedSet): - # pass - nsm_parent_field = 'parent_land_unit' - - def on_trash(self): - ancestors = self.get_ancestors() - for ancestor in ancestors: - ancestor_doc = frappe.get_doc('Land Unit', ancestor) - ancestor_child_features, ancestor_non_child_features = ancestor_doc.feature_seperator(child_feature = self.get('land_unit_name')) - ancestor_features = ancestor_non_child_features - for index,feature in enumerate(ancestor_features): - ancestor_features[index] = json.loads(feature) - ancestor_doc.set_location_value(features = ancestor_features) - ancestor_doc.db_set(fieldname='area', value=ancestor_doc.get('area')-self.get('area'),commit=True) - super(LandUnit, self).on_update() - - def validate(self): - if not self.is_new(): - if not self.get('location'): - features = '' - else: - features = json.loads(self.get('location')).get('features') - new_area = compute_area(features) - self.area_difference = new_area - flt(self.area) - self.area = new_area - - if self.get('parent_land_unit'): - ancestors = self.get_ancestors() - self_features = self.add_child_property() - self_features = set(self_features) - - for ancestor in ancestors: - ancestor_doc = frappe.get_doc('Land Unit', ancestor) - ancestor_child_features, ancestor_non_child_features = ancestor_doc.feature_seperator(child_feature = self.get('land_unit_name')) - ancestor_features = list(set(ancestor_non_child_features)) - child_features = set(ancestor_child_features) - - if not (self_features.issubset(child_features) and child_features.issubset(self_features)): - features_to_be_appended = self_features - child_features - features_to_be_discarded = child_features - self_features - for feature in features_to_be_discarded: - child_features.discard(feature) - for feature in features_to_be_appended: - child_features.add(feature) - child_features = list(child_features) - - ancestor_features.extend(child_features) - for index,feature in enumerate(ancestor_features): - ancestor_features[index] = json.loads(feature) - ancestor_doc.set_location_value(features = ancestor_features) - ancestor_doc.db_set(fieldname='area', value=ancestor_doc.get('area')+\ - self.get('area_difference'),commit=True) - - def set_location_value(self, features): - if not self.get('location'): - self.location = '{"type":"FeatureCollection","features":[]}' - location = json.loads(self.location) - location['features'] = features - self.db_set(fieldname='location', value=json.dumps(location), commit=True) - - def on_update(self): - super(LandUnit, self).on_update() - - def add_child_property(self): - location = self.get('location') - if location: - features = json.loads(location).get('features') - if type(features) != list: - features = json.loads(features) - filter_features = [feature for feature in features if feature.get('properties').get('child_feature') != True] - for index,feature in enumerate(filter_features): - feature['properties'].update({'child_feature': True, 'feature_of': self.land_unit_name}) - filter_features[index] = json.dumps(filter_features[index]) - return filter_features - return [] - - def feature_seperator(self, child_feature=None): - doc = self - child_features = [] - non_child_features = [] - location = doc.get('location') - if location: - features = json.loads(location).get('features') - if type(features) != list: - features = json.loads(features) - for feature in features: - if feature.get('properties').get('feature_of') == child_feature: - child_features.extend([json.dumps(feature)]) - else: - non_child_features.extend([json.dumps(feature)]) - - return child_features, non_child_features - - -def compute_area(features): - layer_area = 0 - for feature in features: - if feature.get('geometry').get('type') == 'Polygon': - layer_area += polygon_area(coords = feature.get('geometry').get('coordinates')) - elif feature.get('geometry').get('type') == 'Point' and feature.get('properties').get('point_type') == 'circle': - layer_area += math.pi * math.pow(feature.get('properties').get('radius'), 2) - return flt(layer_area) - -def rad(angle_in_degrees): - return angle_in_degrees*math.pi/180 - -def polygon_area(coords): - area = 0 - if coords and len(coords) > 0: - area += math.fabs(ring_area(coords[0])); - for i in range(1, len(coords)): - area -= math.fabs(ring_area(coords[i])); - return area; - -def ring_area(coords): - p1 = 0 - p2 = 0 - p3 = 0 - lower_index = 0 - middle_index = 0 - upper_index = 0 - i = 0 - area = 0 - coords_length = len(coords) - if coords_length > 2: - for i in range(0, coords_length): - if i == coords_length - 2: # i = N-2 - lower_index = coords_length - 2; - middle_index = coords_length -1; - upper_index = 0; - elif i == coords_length - 1: # i = N-1 - lower_index = coords_length - 1; - middle_index = 0; - upper_index = 1; - else: # i = 0 to N-3 - lower_index = i; - middle_index = i+1; - upper_index = i+2; - p1 = coords[lower_index]; - p2 = coords[middle_index]; - p3 = coords[upper_index]; - area += ( rad(p3[0]) - rad(p1[0]) ) * math.sin( rad(p2[1])); - - area = area * RADIUS * RADIUS / 2 - return area - -@frappe.whitelist() -def get_children(doctype, parent, is_root=False): - if is_root: - parent = '' - - land_units = frappe.get_list(doctype, - fields = ['name as value', 'is_group as expandable'], - filters= [['ifnull(`parent_land_unit`, "")', '=', parent]], - order_by='name') - - # return nodes - return land_units - - -def on_doctype_update(): - frappe.db.add_index("Land Unit", ["lft", "rgt"]) \ No newline at end of file diff --git a/erpnext/agriculture/doctype/land_unit/land_unit_tree.js b/erpnext/agriculture/doctype/land_unit/land_unit_tree.js deleted file mode 100644 index bf64126a2e..0000000000 --- a/erpnext/agriculture/doctype/land_unit/land_unit_tree.js +++ /dev/null @@ -1,30 +0,0 @@ -frappe.treeview_settings["Land Unit"] = { - get_tree_nodes: "erpnext.agriculture.doctype.land_unit.land_unit.get_children", - ignore_fields:["parent_land_unit"], - get_tree_root: false, - disable_add_node: true, - root_label: "All Land Units", - onload: function(me) { - me.make_tree(); - }, - toolbar: [ - { toggle_btn: true }, - { - label:__("Edit"), - condition: function(node) { return (node.label!='All Land Units'); }, - click: function(node) { - frappe.set_route('Form', 'Land Unit', node.data.value); - } - }, - { - label:__("Add Child"), - condition: function(node) { return node.expandable; }, - click: function(node) { - if(node.label=='All Land Units') node.label=''; - var lu = frappe.new_doc("Land Unit", { - "parent_land_unit": node.label - }); - } - } - ], -}; \ No newline at end of file diff --git a/erpnext/agriculture/doctype/land_unit/test_land_unit.js b/erpnext/agriculture/doctype/land_unit/test_land_unit.js deleted file mode 100644 index f9d3566ac0..0000000000 --- a/erpnext/agriculture/doctype/land_unit/test_land_unit.js +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -// rename this file from _test_[name] to test_[name] to activate -// and remove above this line - -QUnit.test("test: Land Unit", function (assert) { - let done = assert.async(); - - // number of asserts - assert.expect(1); - - frappe.run_serially([ - // insert a new Land Unit - () => frappe.tests.make('Land Unit', [ - // values to be set - {land_unit_name: 'Basil Farm'} - ]), - () => { - assert.equal(cur_frm.doc.name, 'Basil Farm'); - }, - () => done() - ]); - -}); diff --git a/erpnext/agriculture/doctype/land_unit/test_land_unit.py b/erpnext/agriculture/doctype/land_unit/test_land_unit.py deleted file mode 100644 index 005014eb89..0000000000 --- a/erpnext/agriculture/doctype/land_unit/test_land_unit.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals -import json -import frappe -import unittest - -class TestLandUnit(unittest.TestCase): - - def runTest(self): - land_units = ['Basil Farm', 'Division 1', 'Field 1', 'Block 1'] - area = 0 - formatted_land_units = [] - for land_unit in land_units: - doc = frappe.get_doc('Land Unit', land_unit) - doc.save() - area += doc.area - temp = json.loads(doc.location) - temp['features'][0]['properties']['child_feature'] = True - temp['features'][0]['properties']['feature_of'] = land_unit - formatted_land_units.extend(temp['features']) - formatted_land_unit_string = str(formatted_land_units) - test_land = frappe.get_doc('Land Unit', 'Test Land') - self.assertEqual(formatted_land_unit_string, str(json.loads(test_land.get('location'))['features'])) - self.assertEqual(area, test_land.get('area')) diff --git a/erpnext/agriculture/doctype/land_unit/__init__.py b/erpnext/agriculture/doctype/linked_location/__init__.py similarity index 100% rename from erpnext/agriculture/doctype/land_unit/__init__.py rename to erpnext/agriculture/doctype/linked_location/__init__.py diff --git a/erpnext/agriculture/doctype/linked_land_unit/linked_land_unit.json b/erpnext/agriculture/doctype/linked_location/linked_location.json similarity index 87% rename from erpnext/agriculture/doctype/linked_land_unit/linked_land_unit.json rename to erpnext/agriculture/doctype/linked_location/linked_location.json index 63816b8574..56a29d5200 100644 --- a/erpnext/agriculture/doctype/linked_land_unit/linked_land_unit.json +++ b/erpnext/agriculture/doctype/linked_location/linked_location.json @@ -14,11 +14,12 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "land_unit", + "fieldname": "location", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -27,10 +28,10 @@ "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 0, - "label": "Land Unit", + "label": "Location", "length": 0, "no_copy": 0, - "options": "Land Unit", + "options": "Location", "permlevel": 0, "precision": "", "print_hide": 0, @@ -41,6 +42,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -54,10 +56,10 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-12-04 13:25:50.856991", + "modified": "2018-06-20 04:35:51.675244", "modified_by": "Administrator", "module": "Agriculture", - "name": "Linked Land Unit", + "name": "Linked Location", "name_case": "", "owner": "Administrator", "permissions": [], diff --git a/erpnext/agriculture/doctype/linked_land_unit/linked_land_unit.py b/erpnext/agriculture/doctype/linked_location/linked_location.py similarity index 65% rename from erpnext/agriculture/doctype/linked_land_unit/linked_land_unit.py rename to erpnext/agriculture/doctype/linked_location/linked_location.py index 266edb9b12..3e49d3e18f 100644 --- a/erpnext/agriculture/doctype/linked_land_unit/linked_land_unit.py +++ b/erpnext/agriculture/doctype/linked_location/linked_location.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt from __future__ import unicode_literals import frappe from frappe.model.document import Document -class LinkedLandUnit(Document): +class LinkedLocation(Document): pass diff --git a/erpnext/agriculture/doctype/linked_land_unit/__init__.py b/erpnext/assets/doctype/linked_location/__init__.py similarity index 100% rename from erpnext/agriculture/doctype/linked_land_unit/__init__.py rename to erpnext/assets/doctype/linked_location/__init__.py diff --git a/erpnext/assets/doctype/linked_location/linked_location.json b/erpnext/assets/doctype/linked_location/linked_location.json new file mode 100644 index 0000000000..f04a79e593 --- /dev/null +++ b/erpnext/assets/doctype/linked_location/linked_location.json @@ -0,0 +1,74 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2017-11-22 14:34:59.461273", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "location", + "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": "Location", + "length": 0, + "no_copy": 0, + "options": "Location", + "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 + } + ], + "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": "2018-06-20 04:35:59.514281", + "modified_by": "Administrator", + "module": "Assets", + "name": "Linked Location", + "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": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/assets/doctype/linked_location/linked_location.py b/erpnext/assets/doctype/linked_location/linked_location.py new file mode 100644 index 0000000000..3e49d3e18f --- /dev/null +++ b/erpnext/assets/doctype/linked_location/linked_location.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class LinkedLocation(Document): + pass diff --git a/erpnext/assets/doctype/location/location.js b/erpnext/assets/doctype/location/location.js index c3783dfae7..0f069b2fd8 100644 --- a/erpnext/assets/doctype/location/location.js +++ b/erpnext/assets/doctype/location/location.js @@ -2,7 +2,23 @@ // For license information, please see license.txt frappe.ui.form.on('Location', { - refresh: function(frm) { + setup: function (frm) { + frm.set_query("parent_location", function () { + return { + "filters": { + "is_group": 1 + } + }; + }); + }, - } + onload_post_render(frm) { + if (!frm.doc.location && frm.doc.latitude && frm.doc.longitude) { + frm.fields_dict.location.map.setView([frm.doc.latitude, frm.doc.longitude], 13); + } + else { + frm.doc.latitude = frm.fields_dict.location.map.getCenter()['lat']; + frm.doc.longitude = frm.fields_dict.location.map.getCenter()['lng']; + } + }, }); diff --git a/erpnext/assets/doctype/location/location.json b/erpnext/assets/doctype/location/location.json index d83fdf3667..5dc13062b2 100644 --- a/erpnext/assets/doctype/location/location.json +++ b/erpnext/assets/doctype/location/location.json @@ -1,306 +1,708 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "field:location_name", - "beta": 0, - "creation": "2018-05-07 12:49:22.595974", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:location_name", + "beta": 0, + "creation": "2018-05-07 12:49:22.595974", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "location_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": "Location 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 - }, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "location_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": "Location Name", + "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": 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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "parent_location", + "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": "Parent Location", + "length": 0, + "no_copy": 0, + "options": "Location", + "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 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "parent_location", - "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": "Parent Location", - "length": 0, - "no_copy": 0, - "options": "Location", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "cb_details", + "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 - }, + }, { - "allow_bulk_edit": 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": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "Check if it is a hydroponic unit", + "fieldname": "is_container", + "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 Container", + "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 - }, + }, { - "allow_bulk_edit": 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": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 1, + "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": 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 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "old_parent", - "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": "Old Parent", - "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sb_location_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": "Location 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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "parent_location.latitude", + "fieldname": "latitude", + "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": "Latitude", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "parent_location.longitude", + "fieldname": "longitude", + "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": "Longitude", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "cb_latlong", + "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, + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "area", + "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": "Area", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.area", + "fieldname": "area_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": "Area UOM", + "length": 0, + "no_copy": 0, + "options": "UOM", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sb_geolocation", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "location", + "fieldtype": "Geolocation", + "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": "Location", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "tree_details", + "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, + "label": "Tree 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 + }, + { + "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": 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, + "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": 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, + "fieldname": "old_parent", + "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": "Old Parent", + "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 } - ], - "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-05-07 19:21:06.051414", - "modified_by": "Administrator", - "module": "Assets", - "name": "Location", - "name_case": "", - "owner": "Administrator", + ], + "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-07-11 13:36:30.999405", + "modified_by": "Administrator", + "module": "Assets", + "name": "Location", + "name_case": "Title 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": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "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, "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": "Stock User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "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": "Stock 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": "Accounts User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "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": "Accounts 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": "Stock Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "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": "Stock Manager", + "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": "Agriculture Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "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": "Agriculture User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/assets/doctype/location/location.py b/erpnext/assets/doctype/location/location.py index 86542cbe12..4d73f1190e 100644 --- a/erpnext/assets/doctype/location/location.py +++ b/erpnext/assets/doctype/location/location.py @@ -3,23 +3,197 @@ # For license information, please see license.txt from __future__ import unicode_literals + +import json +import math + import frappe +from frappe import _ from frappe.model.document import Document -from frappe.utils.nestedset import NestedSet +from frappe.utils import flt +from frappe.utils.nestedset import NestedSet, update_nsm + +EARTH_RADIUS = 6378137 + class Location(NestedSet): nsm_parent_field = 'parent_location' + def validate(self): + self.calculate_location_area() + + if not self.is_new() and self.get('parent_location'): + self.update_ancestor_location_features() + def on_update(self): + # super(Location, self).on_update() NestedSet.on_update(self) def on_trash(self): NestedSet.validate_if_child_exists(self) - frappe.utils.nestedset.update_nsm(self) + update_nsm(self) + self.remove_ancestor_location_features() + # super(Location, self).on_update() + + def calculate_location_area(self): + features = self.get_location_features() + new_area = compute_area(features) + + self.area_difference = new_area - flt(self.area) + self.area = new_area + + def get_location_features(self): + if not self.location: + return [] + + features = json.loads(self.location).get('features') + + if not isinstance(features, list): + features = json.loads(features) + + return features + + def set_location_features(self, features): + if not self.location: + self.location = '{"type":"FeatureCollection","features":[]}' + + location = json.loads(self.location) + location['features'] = features + + self.db_set('location', json.dumps(location), commit=True) + + def update_ancestor_location_features(self): + self_features = set(self.add_child_property()) + + for ancestor in self.get_ancestors(): + ancestor_doc = frappe.get_doc('Location', ancestor) + child_features, ancestor_features = ancestor_doc.feature_seperator(child_feature=self.name) + + ancestor_features = list(set(ancestor_features)) + child_features = set(child_features) + + if self_features != child_features: + features_to_be_appended = self_features - child_features + features_to_be_discarded = child_features - self_features + + for feature in features_to_be_discarded: + child_features.discard(feature) + + for feature in features_to_be_appended: + child_features.add(feature) + + ancestor_features.extend(list(child_features)) + + for index, feature in enumerate(ancestor_features): + ancestor_features[index] = json.loads(feature) + + ancestor_doc.set_location_features(features=ancestor_features) + ancestor_doc.db_set('area', ancestor_doc.area + self.area_difference, commit=True) + + def remove_ancestor_location_features(self): + for ancestor in self.get_ancestors(): + ancestor_doc = frappe.get_doc('Location', ancestor) + child_features, ancestor_features = ancestor_doc.feature_seperator(child_feature=self.name) + + for index, feature in enumerate(ancestor_features): + ancestor_features[index] = json.loads(feature) + + ancestor_doc.set_location_features(features=ancestor_features) + ancestor_doc.db_set('area', ancestor_doc.area - self.area, commit=True) + + def add_child_property(self): + features = self.get_location_features() + filter_features = [feature for feature in features if not feature.get('properties').get('child_feature')] + + for index, feature in enumerate(filter_features): + feature['properties'].update({'child_feature': True, 'feature_of': self.location_name}) + filter_features[index] = json.dumps(filter_features[index]) + + return filter_features + + def feature_seperator(self, child_feature=None): + child_features, non_child_features = [], [] + features = self.get_location_features() + + for feature in features: + if feature.get('properties').get('feature_of') == child_feature: + child_features.extend([json.dumps(feature)]) + else: + non_child_features.extend([json.dumps(feature)]) + + return child_features, non_child_features + + +def compute_area(features): + """ + Calculate the total area for a set of location features. + Reference from https://github.com/scisco/area. + + Args: + `features` (list of dict): Features marked on the map as + GeoJSON data + + Returns: + float: The approximate signed geodesic area (in sq. meters) + """ + + layer_area = 0.0 + + for feature in features: + feature_type = feature.get('geometry', {}).get('type') + + if feature_type == 'Polygon': + layer_area += _polygon_area(coords=feature.get('geometry').get('coordinates')) + elif feature_type == 'Point' and feature.get('properties').get('point_type') == 'circle': + layer_area += math.pi * math.pow(feature.get('properties').get('radius'), 2) + + return layer_area + + +def _polygon_area(coords): + if not coords: + return 0 + + area = abs(_ring_area(coords[0])) + + for i in range(1, len(coords)): + area -= abs(_ring_area(coords[i])) + + return area + + +def _ring_area(coords): + area = 0.0 + coords_length = len(coords) + + if coords_length > 2: + for i in range(coords_length): + if i == coords_length - 2: # i = N-2 + lower_index = coords_length - 2 + middle_index = coords_length - 1 + upper_index = 0 + elif i == coords_length - 1: # i = N-1 + lower_index = coords_length - 1 + middle_index = 0 + upper_index = 1 + else: # i = 0 to N-3 + lower_index = i + middle_index = i + 1 + upper_index = i + 2 + + p1 = coords[lower_index] + p2 = coords[middle_index] + p3 = coords[upper_index] + area += (math.radians(p3[0]) - math.radians(p1[0])) * math.sin(math.radians(p2[1])) + + area = area * EARTH_RADIUS * EARTH_RADIUS / 2 + + return area + @frappe.whitelist() def get_children(doctype, parent=None, location=None, is_root=False): - if parent == None or parent == "All Locations": + if parent is None or parent == "All Locations": parent = "" return frappe.db.sql(""" @@ -31,9 +205,10 @@ def get_children(doctype, parent=None, location=None, is_root=False): where ifnull(parent_location, "")="{parent}" """.format( - doctype = frappe.db.escape(doctype), - parent=frappe.db.escape(parent) - ), as_dict=1) + doctype=frappe.db.escape(doctype), + parent=frappe.db.escape(parent) + ), as_dict=1) + @frappe.whitelist() def add_node(): @@ -44,4 +219,8 @@ def add_node(): if args.parent_location == 'All Locations': args.parent_location = None - frappe.get_doc(args).insert() \ No newline at end of file + frappe.get_doc(args).insert() + + +def on_doctype_update(): + frappe.db.add_index("Location", ["lft", "rgt"]) diff --git a/erpnext/assets/doctype/location/location_tree.js b/erpnext/assets/doctype/location/location_tree.js index cbd8f1067e..b405afd1dd 100644 --- a/erpnext/assets/doctype/location/location_tree.js +++ b/erpnext/assets/doctype/location/location_tree.js @@ -1,14 +1,14 @@ frappe.treeview_settings["Location"] = { - ignore_fields:["parent_location"], + ignore_fields: ["parent_location"], get_tree_nodes: 'erpnext.assets.doctype.location.location.get_children', add_tree_node: 'erpnext.assets.doctype.location.location.add_node', filters: [ { fieldname: "location", - fieldtype:"Link", + fieldtype: "Link", options: "Location", label: __("Location"), - get_query: function() { + get_query: function () { return { filters: [["Location", "is_group", "=", 1]] }; @@ -21,13 +21,13 @@ frappe.treeview_settings["Location"] = { menu_items: [ { label: __("New Location"), - action: function() { + action: function () { frappe.new_doc("Location", true); }, condition: 'frappe.boot.user.can_create.indexOf("Location") !== -1' } ], - onload: function(treeview) { + onload: function (treeview) { treeview.make_tree(); } }; \ No newline at end of file diff --git a/erpnext/assets/doctype/location/test_location.js b/erpnext/assets/doctype/location/test_location.js index 236b5c65b0..3c06b63e82 100644 --- a/erpnext/assets/doctype/location/test_location.js +++ b/erpnext/assets/doctype/location/test_location.js @@ -12,10 +12,10 @@ QUnit.test("test: Location", function (assert) { // insert a new Location () => frappe.tests.make('Location', [ // values to be set - {key: 'value'} + { location_name: 'Basil Farm' } ]), () => { - assert.equal(cur_frm.doc.key, 'value'); + assert.equal(cur_frm.doc.name, 'Basil Farm'); }, () => done() ]); diff --git a/erpnext/assets/doctype/location/test_location.py b/erpnext/assets/doctype/location/test_location.py index 9a46fd93ef..6d8dd69cb8 100644 --- a/erpnext/assets/doctype/location/test_location.py +++ b/erpnext/assets/doctype/location/test_location.py @@ -3,8 +3,29 @@ # See license.txt from __future__ import unicode_literals -import frappe +import json import unittest +import frappe + + class TestLocation(unittest.TestCase): - pass + def runTest(self): + locations = ['Basil Farm', 'Division 1', 'Field 1', 'Block 1'] + area = 0 + formatted_locations = [] + + for location in locations: + doc = frappe.get_doc('Location', location) + doc.save() + area += doc.area + temp = json.loads(doc.location) + temp['features'][0]['properties']['child_feature'] = True + temp['features'][0]['properties']['feature_of'] = location + formatted_locations.extend(temp['features']) + + formatted_location_string = str(formatted_locations) + test_location = frappe.get_doc('Location', 'Test Location') + + self.assertEqual(formatted_location_string, str(json.loads(test_location.get('location'))['features'])) + self.assertEqual(area, test_location.get('area')) diff --git a/erpnext/agriculture/doctype/land_unit/test_records.json b/erpnext/assets/doctype/location/test_records.json similarity index 74% rename from erpnext/agriculture/doctype/land_unit/test_records.json rename to erpnext/assets/doctype/location/test_records.json index e7fed9f946..3827225251 100644 --- a/erpnext/agriculture/doctype/land_unit/test_records.json +++ b/erpnext/assets/doctype/location/test_records.json @@ -1,42 +1,42 @@ [ { - "doctype": "Land Unit", - "land_unit_name": "Test Land", + "doctype": "Location", + "location_name": "Test Location", "is_group": 1, "is_container": 1 }, { - "doctype": "Land Unit", - "land_unit_name": "Basil Farm", + "doctype": "Location", + "location_name": "Basil Farm", "location": "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"point_type\":\"circle\",\"radius\":884.5625420736483},\"geometry\":{\"type\":\"Point\",\"coordinates\":[72.875834,19.100566]}}]}", - "parent_land_unit": "Test Land", - "parent": "Test Land", + "parent_location": "Test Location", + "parent": "Test Location", "is_group": 1, "is_container": 1 }, { - "doctype": "Land Unit", - "land_unit_name": "Division 1", + "doctype": "Location", + "location_name": "Division 1", "location": "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"point_type\":\"circle\",\"radius\":542.3424997060739},\"geometry\":{\"type\":\"Point\",\"coordinates\":[72.852359,19.11557]}}]}", - "parent_land_unit": "Basil Farm", + "parent_location": "Basil Farm", "parent": "Basil Farm", "is_group": 1, "is_container": 1 }, { - "doctype": "Land Unit", - "land_unit_name": "Field 1", + "doctype": "Location", + "location_name": "Field 1", "location": "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[72.846758,19.118287],[72.846758,19.121206],[72.850535,19.121206],[72.850535,19.118287],[72.846758,19.118287]]]}}]}", - "parent_land_unit": "Division 1", + "parent_location": "Division 1", "parent": "Division 1", "is_group": 1, "is_container": 1 }, { - "doctype": "Land Unit", - "land_unit_name": "Block 1", + "doctype": "Location", + "location_name": "Block 1", "location": "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[72.921495,19.073313],[72.924929,19.068121],[72.934713,19.06585],[72.929392,19.05579],[72.94158,19.056926],[72.951365,19.095213],[72.921495,19.073313]]]}}]}", - "parent_land_unit": "Field 1", + "parent_location": "Field 1", "parent": "Field 1", "is_group": 0, "is_container": 1 diff --git a/erpnext/config/agriculture.py b/erpnext/config/agriculture.py index 20ee7cf215..a6bc3028d8 100644 --- a/erpnext/config/agriculture.py +++ b/erpnext/config/agriculture.py @@ -16,7 +16,7 @@ def get_data(): }, { "type": "doctype", - "name": "Land Unit", + "name": "Location" } ] }, diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py index db6975ee06..f98731674a 100644 --- a/erpnext/config/desktop.py +++ b/erpnext/config/desktop.py @@ -398,13 +398,13 @@ def get_data(): "hidden": 1 }, { - "module_name": "Land Unit", - "_doctype": "Land Unit", - "label": _("Land Unit"), + "module_name": "Location", + "_doctype": "Location", + "label": _("Location"), "color": "#8BC34A", "icon": "fa fa-map", "type": "list", - "link": "List/Land Unit", + "link": "List/Location", "hidden": 1 }, { diff --git a/erpnext/domains/agriculture.py b/erpnext/domains/agriculture.py index d605ac7820..594624778d 100644 --- a/erpnext/domains/agriculture.py +++ b/erpnext/domains/agriculture.py @@ -5,7 +5,7 @@ data = { 'Crop Cycle', 'Fertilizer', 'Item', - 'Land Unit', + 'Location', 'Disease', 'Plant Analysis', 'Soil Analysis', diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 3be91c0639..fa6acd7aba 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -553,4 +553,5 @@ erpnext.patches.v11_0.rename_asset_adjustment_doctype execute:frappe.db.sql("update `tabDesktop Icon` set type = 'module' where module_name = 'Restaurant'") erpnext.patches.v11_0.set_salary_component_properties erpnext.patches.v11_0.set_user_permissions_for_department -erpnext.patches.v11_0.hr_ux_cleanups \ No newline at end of file +erpnext.patches.v11_0.hr_ux_cleanups +erpnext.patches.v11_0.merge_land_unit_with_location diff --git a/erpnext/patches/v11_0/merge_land_unit_with_location.py b/erpnext/patches/v11_0/merge_land_unit_with_location.py new file mode 100644 index 0000000000..999fb1f18d --- /dev/null +++ b/erpnext/patches/v11_0/merge_land_unit_with_location.py @@ -0,0 +1,60 @@ +# Copyright (c) 2018, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe +from frappe.model.rename_doc import rename_doc +from frappe.model.utils.rename_field import rename_field + + +def execute(): + # Rename and reload the Land Unit and Linked Land Unit doctypes + if frappe.db.table_exists('Land Unit') and not frappe.db.table_exists('Location'): + rename_doc('DocType', 'Land Unit', 'Location', force=True) + + frappe.reload_doc('assets', 'doctype', 'location') + + if frappe.db.table_exists('Linked Land Unit') and not frappe.db.table_exists('Linked Location'): + rename_doc('DocType', 'Linked Land Unit', 'Linked Location', force=True) + + frappe.reload_doc('assets', 'doctype', 'linked_location') + + # Rename the fields in related doctypes + if 'linked_land_unit' in frappe.db.get_table_columns('Crop Cycle'): + rename_field('Crop Cycle', 'linked_land_unit', 'linked_location') + + if 'land_unit' in frappe.db.get_table_columns('Linked Location'): + rename_field('Linked Location', 'land_unit', 'location') + + if not frappe.db.exists("Location", "All Land Units"): + frappe.get_doc({"doctype": "Location", "is_group": True, "location_name": "All Land Units"}).insert(ignore_permissions=True) + + if frappe.db.table_exists('Land Unit'): + land_units = frappe.get_all('Land Unit', fields=['*'], order_by='lft') + + for land_unit in land_units: + if not frappe.db.exists('Location', land_unit.get('land_unit_name')): + frappe.get_doc({ + 'doctype': 'Location', + 'location_name': land_unit.get('land_unit_name'), + 'parent_location': land_unit.get('parent_land_unit') or "All Land Units", + 'is_container': land_unit.get('is_container'), + 'is_group': land_unit.get('is_group'), + 'latitude': land_unit.get('latitude'), + 'longitude': land_unit.get('longitude'), + 'area': land_unit.get('area'), + 'location': land_unit.get('location'), + 'lft': land_unit.get('lft'), + 'rgt': land_unit.get('rgt') + }).insert(ignore_permissions=True) + + # frappe.db.sql("""update `tabDesktop Icon` set label='Location', module_name='Location' where label='Land Unit'""") + frappe.db.sql("""update `tabDesktop Icon` set link='List/Location' where link='List/Land Unit'""") + + # Delete the Land Unit and Linked Land Unit doctypes + if frappe.db.table_exists('Land Unit'): + frappe.delete_doc('DocType', 'Land Unit', force=1) + + if frappe.db.table_exists('Linked Land Unit'): + frappe.delete_doc('DocType', 'Linked Land Unit', force=1) diff --git a/erpnext/tests/server/agriculture.txt b/erpnext/tests/server/agriculture.txt index 3aae85a343..29dc9ab62d 100644 --- a/erpnext/tests/server/agriculture.txt +++ b/erpnext/tests/server/agriculture.txt @@ -1,5 +1,4 @@ Disease Crop -Land Unit Crop Cycle Soil Texture \ No newline at end of file