[Agriculture] Sort crop tasks chronologically and optimize disease task creation (#14367)
* Improve max crop period check and sort agriculture tasks chronologically * Reformat crop cycle logic and add field to optimize task creation
This commit is contained in:
parent
ebb530385a
commit
ca8138fd13
@ -3,23 +3,31 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _
|
|
||||||
|
|
||||||
class Crop(Document):
|
class Crop(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
max_period = 0
|
self.validate_crop_tasks()
|
||||||
|
|
||||||
|
def validate_crop_tasks(self):
|
||||||
for task in self.agriculture_task:
|
for task in self.agriculture_task:
|
||||||
# validate start_day is not > end_day
|
|
||||||
if task.start_day > task.end_day:
|
if task.start_day > task.end_day:
|
||||||
frappe.throw(_("Start day is greater than end day in task '{0}'").format(task.task_name))
|
frappe.throw(_("Start day is greater than end day in task '{0}'").format(task.task_name))
|
||||||
# to calculate the period of the Crop Cycle
|
|
||||||
if task.end_day > max_period: max_period = task.end_day
|
# Verify that the crop period is correct
|
||||||
if max_period > self.period: self.period = max_period
|
max_crop_period = max([task.end_day for task in self.agriculture_task])
|
||||||
|
self.period = max(self.period, max_crop_period)
|
||||||
|
|
||||||
|
# Sort the crop tasks based on start days,
|
||||||
|
# maintaining the order for same-day tasks
|
||||||
|
self.agriculture_task.sort(key=lambda task: task.start_day)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_item_details(item_code):
|
def get_item_details(item_code):
|
||||||
item = frappe.get_doc('Item', item_code)
|
item = frappe.get_doc('Item', item_code)
|
||||||
return { "uom": item.stock_uom, "rate": item.valuation_rate }
|
return {"uom": item.stock_uom, "rate": item.valuation_rate}
|
||||||
|
|||||||
@ -3,43 +3,48 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import ast
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
import ast
|
from frappe.utils import add_days
|
||||||
|
|
||||||
|
|
||||||
class CropCycle(Document):
|
class CropCycle(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if self.is_new():
|
self.set_missing_values()
|
||||||
crop = frappe.get_doc('Crop', self.crop)
|
|
||||||
self.create_project(crop.period, crop.agriculture_task)
|
|
||||||
if not self.crop_spacing_uom:
|
|
||||||
self.crop_spacing_uom = crop.crop_spacing_uom
|
|
||||||
if not self.row_spacing_uom:
|
|
||||||
self.row_spacing_uom = crop.row_spacing_uom
|
|
||||||
if not self.project:
|
|
||||||
self.project = self.name
|
|
||||||
disease = []
|
|
||||||
for detected_disease in self.detected_disease:
|
|
||||||
disease.append(detected_disease.name)
|
|
||||||
if disease != []:
|
|
||||||
self.update_disease(disease)
|
|
||||||
else:
|
|
||||||
old_disease, new_disease = [], []
|
|
||||||
for detected_disease in self.detected_disease:
|
|
||||||
new_disease.append(detected_disease.name)
|
|
||||||
for detected_disease in self.get_doc_before_save().get('detected_disease'):
|
|
||||||
old_disease.append(detected_disease.name)
|
|
||||||
if list(set(new_disease)-set(old_disease)) != []:
|
|
||||||
self.update_disease(list(set(new_disease)-set(old_disease)))
|
|
||||||
frappe.msgprint(_("All tasks for the detected diseases were imported"))
|
|
||||||
|
|
||||||
def update_disease(self, disease_hashes):
|
def after_insert(self):
|
||||||
new_disease = []
|
self.create_crop_cycle_project()
|
||||||
|
self.create_tasks_for_diseases()
|
||||||
|
|
||||||
|
def on_update(self):
|
||||||
|
self.create_tasks_for_diseases()
|
||||||
|
|
||||||
|
def set_missing_values(self):
|
||||||
|
crop = frappe.get_doc('Crop', self.crop)
|
||||||
|
|
||||||
|
if not self.crop_spacing_uom:
|
||||||
|
self.crop_spacing_uom = crop.crop_spacing_uom
|
||||||
|
|
||||||
|
if not self.row_spacing_uom:
|
||||||
|
self.row_spacing_uom = crop.row_spacing_uom
|
||||||
|
|
||||||
|
def create_crop_cycle_project(self):
|
||||||
|
crop = frappe.get_doc('Crop', self.crop)
|
||||||
|
|
||||||
|
self.project = self.create_project(crop.period, crop.agriculture_task)
|
||||||
|
self.create_task(crop.agriculture_task, self.project, self.start_date)
|
||||||
|
|
||||||
|
def create_tasks_for_diseases(self):
|
||||||
for disease in self.detected_disease:
|
for disease in self.detected_disease:
|
||||||
for disease_hash in disease_hashes:
|
if not disease.tasks_created:
|
||||||
if disease.name == disease_hash:
|
self.import_disease_tasks(disease.disease, disease.start_date)
|
||||||
self.import_disease_tasks(disease.disease, disease.start_date)
|
disease.tasks_created = True
|
||||||
|
|
||||||
|
frappe.msgprint(_("Tasks have been created for managing the {0} disease (on row {1})".format(disease.disease, disease.idx)))
|
||||||
|
|
||||||
def import_disease_tasks(self, disease, start_date):
|
def import_disease_tasks(self, disease, start_date):
|
||||||
disease_doc = frappe.get_doc('Disease', disease)
|
disease_doc = frappe.get_doc('Disease', disease)
|
||||||
@ -47,58 +52,77 @@ class CropCycle(Document):
|
|||||||
|
|
||||||
def create_project(self, period, crop_tasks):
|
def create_project(self, period, crop_tasks):
|
||||||
project = frappe.new_doc("Project")
|
project = frappe.new_doc("Project")
|
||||||
project.project_name = self.title
|
project.update({
|
||||||
project.expected_start_date = self.start_date
|
"project_name": self.title,
|
||||||
project.expected_end_date = frappe.utils.data.add_days(self.start_date, period-1)
|
"expected_start_date": self.start_date,
|
||||||
|
"expected_end_date": add_days(self.start_date, period - 1)
|
||||||
|
})
|
||||||
project.insert()
|
project.insert()
|
||||||
self.create_task(crop_tasks, project.as_dict.im_self.name, self.start_date)
|
|
||||||
return project.as_dict.im_self.name
|
return project.name
|
||||||
|
|
||||||
def create_task(self, crop_tasks, project_name, start_date):
|
def create_task(self, crop_tasks, project_name, start_date):
|
||||||
for crop_task in crop_tasks:
|
for crop_task in crop_tasks:
|
||||||
task = frappe.new_doc("Task")
|
task = frappe.new_doc("Task")
|
||||||
task.subject = crop_task.get("task_name")
|
task.update({
|
||||||
task.priority = crop_task.get("priority")
|
"subject": crop_task.get("task_name"),
|
||||||
task.project = project_name
|
"priority": crop_task.get("priority"),
|
||||||
task.exp_start_date = frappe.utils.data.add_days(start_date, crop_task.get("start_day")-1)
|
"project": project_name,
|
||||||
task.exp_end_date = frappe.utils.data.add_days(start_date, crop_task.get("end_day")-1)
|
"exp_start_date": add_days(start_date, crop_task.get("start_day") - 1),
|
||||||
|
"exp_end_date": add_days(start_date, crop_task.get("end_day") - 1)
|
||||||
|
})
|
||||||
task.insert()
|
task.insert()
|
||||||
|
|
||||||
def reload_linked_analysis(self):
|
def reload_linked_analysis(self):
|
||||||
linked_doctypes = ['Soil Texture', 'Soil Analysis', 'Plant Analysis']
|
linked_doctypes = ['Soil Texture', 'Soil Analysis', 'Plant Analysis']
|
||||||
required_fields = ['location', 'name', 'collection_datetime']
|
required_fields = ['location', 'name', 'collection_datetime']
|
||||||
output = {}
|
output = {}
|
||||||
|
|
||||||
for doctype in linked_doctypes:
|
for doctype in linked_doctypes:
|
||||||
output[doctype] = frappe.get_all(doctype, fields=required_fields)
|
output[doctype] = frappe.get_all(doctype, fields=required_fields)
|
||||||
|
|
||||||
output['Land Unit'] = []
|
output['Land Unit'] = []
|
||||||
|
|
||||||
for land in self.linked_land_unit:
|
for land in self.linked_land_unit:
|
||||||
output['Land Unit'].append(frappe.get_doc('Land Unit', land.land_unit))
|
output['Land Unit'].append(frappe.get_doc('Land Unit', land.land_unit))
|
||||||
|
|
||||||
frappe.publish_realtime("List of Linked Docs", output, user=frappe.session.user)
|
frappe.publish_realtime("List of Linked Docs",
|
||||||
|
output, user=frappe.session.user)
|
||||||
|
|
||||||
def append_to_child(self, obj_to_append):
|
def append_to_child(self, obj_to_append):
|
||||||
for doctype in obj_to_append:
|
for doctype in obj_to_append:
|
||||||
for doc_name in set(obj_to_append[doctype]):
|
for doc_name in set(obj_to_append[doctype]):
|
||||||
self.append(doctype, {doctype: doc_name})
|
self.append(doctype, {doctype: doc_name})
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def get_coordinates(self, doc):
|
|
||||||
return ast.literal_eval(doc.location).get('features')[0].get('geometry').get('coordinates')
|
|
||||||
|
|
||||||
def get_geometry_type(self, doc):
|
def get_coordinates(doc):
|
||||||
return ast.literal_eval(doc.location).get('features')[0].get('geometry').get('type')
|
return ast.literal_eval(doc.location).get('features')[0].get('geometry').get('coordinates')
|
||||||
|
|
||||||
def is_in_land_unit(self, point, vs):
|
|
||||||
x, y = point
|
def get_geometry_type(doc):
|
||||||
inside = False
|
return ast.literal_eval(doc.location).get('features')[0].get('geometry').get('type')
|
||||||
j = len(vs)-1
|
|
||||||
i = 0
|
|
||||||
while i < len(vs):
|
def is_in_land_unit(point, vs):
|
||||||
xi, yi = vs[i]
|
x, y = point
|
||||||
xj, yj = vs[j]
|
inside = False
|
||||||
intersect = ((yi > y) != (yj > y)) and (x < (xj - xi) * (y - yi) / (yj - yi) + xi)
|
|
||||||
if intersect:
|
j = len(vs) - 1
|
||||||
inside = not inside
|
i = 0
|
||||||
i = j
|
|
||||||
j += 1
|
while i < len(vs):
|
||||||
return inside
|
xi, yi = vs[i]
|
||||||
|
xj, yj = vs[j]
|
||||||
|
|
||||||
|
intersect = ((yi > y) != (yj > y)) and (
|
||||||
|
x < (xj - xi) * (y - yi) / (yj - yi) + xi)
|
||||||
|
|
||||||
|
if intersect:
|
||||||
|
inside = not inside
|
||||||
|
|
||||||
|
i = j
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
return inside
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@ -41,10 +42,12 @@
|
|||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
@ -71,6 +74,40 @@
|
|||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 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": "tasks_created",
|
||||||
|
"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": "Tasks Created",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 1,
|
||||||
|
"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
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -84,7 +121,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-11-26 21:10:14.753511",
|
"modified": "2018-06-06 02:24:52.131482",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Agriculture",
|
"module": "Agriculture",
|
||||||
"name": "Detected Disease",
|
"name": "Detected Disease",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user