Merge pull request #25358 from noahjacob/maintenance_feat

refactor: maintenance schedule and visit enhancements.
This commit is contained in:
Marica 2021-05-30 01:20:30 +05:30 committed by GitHub
commit 42b2ea556f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1138 additions and 2601 deletions

View File

@ -2,40 +2,36 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.maintenance");
frappe.ui.form.on('Maintenance Schedule', {
setup: function(frm) {
setup: function (frm) {
frm.set_query('contact_person', erpnext.queries.contact_query);
frm.set_query('customer_address', erpnext.queries.address_query);
frm.set_query('customer', erpnext.queries.customer);
frm.add_fetch('item_code', 'item_name', 'item_name');
frm.add_fetch('item_code', 'description', 'description');
},
onload: function(frm) {
onload: function (frm) {
if (!frm.doc.status) {
frm.set_value({status:'Draft'});
frm.set_value({ status: 'Draft' });
}
if (frm.doc.__islocal) {
frm.set_value({transaction_date: frappe.datetime.get_today()});
frm.set_value({ transaction_date: frappe.datetime.get_today() });
}
},
refresh: function(frm) {
refresh: function (frm) {
setTimeout(() => {
frm.toggle_display('generate_schedule', !(frm.is_new()));
frm.toggle_display('schedule', !(frm.is_new()));
},10);
}, 10);
},
customer: function(frm) {
customer: function (frm) {
erpnext.utils.get_party_details(frm)
},
customer_address: function(frm) {
customer_address: function (frm) {
erpnext.utils.get_address_display(frm, 'customer_address', 'address_display');
},
contact_person: function(frm) {
contact_person: function (frm) {
erpnext.utils.get_contact_details(frm);
},
generate_schedule: function(frm) {
generate_schedule: function (frm) {
if (frm.is_new()) {
frappe.msgprint(__('Please save first'));
} else {
@ -46,14 +42,14 @@ frappe.ui.form.on('Maintenance Schedule', {
// TODO commonify this code
erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({
refresh: function() {
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
refresh: function () {
frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer' };
var me = this;
if (this.frm.doc.docstatus === 0) {
this.frm.add_custom_button(__('Sales Order'),
function() {
function () {
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
source_doctype: "Sales Order",
@ -68,52 +64,107 @@ erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({
});
}, __("Get Items From"));
} else if (this.frm.doc.docstatus === 1) {
this.frm.add_custom_button(__('Create Maintenance Visit'), function() {
frappe.model.open_mapped_doc({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
source_name: me.frm.doc.name,
frm: me.frm
let schedules = me.frm.doc.schedules;
let flag = schedules.some(schedule => schedule.completion_status === "Pending");
if (flag) {
this.frm.add_custom_button(__('Maintenance Visit'), function () {
let options = "";
me.frm.call('get_pending_data', {data_type: "items"}).then(r => {
options = r.message;
let schedule_id = "";
let d = new frappe.ui.Dialog({
title: __("Enter Visit Details"),
fields: [{
fieldtype: "Select",
fieldname: "item_name",
label: __("Item Name"),
options: options,
reqd: 1,
onchange: function () {
let field = d.get_field("scheduled_date");
me.frm.call('get_pending_data',
{
item_name: this.value,
data_type: "date"
}).then(r => {
field.df.options = r.message;
field.refresh();
});
}
},
{
label: __('Scheduled Date'),
fieldname: 'scheduled_date',
fieldtype: 'Select',
options: "",
reqd: 1,
onchange: function () {
let field = d.get_field('item_name');
me.frm.call(
'get_pending_data',
{
item_name: field.value,
s_date: this.value,
data_type: "id"
}).then(r => {
schedule_id = r.message;
});
}
},
],
primary_action_label: 'Create Visit',
primary_action(values) {
frappe.call({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
args: {
item_name: values.item_name,
s_id: schedule_id,
source_name: me.frm.doc.name,
},
callback: function (r) {
if (!r.exc) {
frappe.model.sync(r.message);
frappe.set_route("Form", r.message.doctype, r.message.name);
}
}
});
d.hide();
}
});
d.show();
});
}, __('Create'));
}, __('Create'));
}
}
},
start_date: function(doc, cdt, cdn) {
start_date: function (doc, cdt, cdn) {
this.set_no_of_visits(doc, cdt, cdn);
},
end_date: function(doc, cdt, cdn) {
end_date: function (doc, cdt, cdn) {
this.set_no_of_visits(doc, cdt, cdn);
},
periodicity: function(doc, cdt, cdn) {
periodicity: function (doc, cdt, cdn) {
this.set_no_of_visits(doc, cdt, cdn);
},
no_of_visits: function (doc, cdt, cdn) {
this.set_no_of_visits(doc, cdt, cdn);
},
set_no_of_visits: function(doc, cdt, cdn) {
set_no_of_visits: function (doc, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
if (item.start_date && item.end_date && item.periodicity) {
if(item.start_date > item.end_date) {
frappe.msgprint(__("Row {0}:Start Date must be before End Date", [item.idx]));
return;
}
var date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1;
var days_in_period = {
"Weekly": 7,
"Monthly": 30,
"Quarterly": 91,
"Half Yearly": 182,
"Yearly": 365
}
var no_of_visits = cint(date_diff / days_in_period[item.periodicity]);
frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits);
let me = this;
if (item.start_date && item.periodicity) {
me.frm.call('validate_end_date_visits');
}
},
});
$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({frm: cur_frm}));
$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({ frm: cur_frm }));

View File

@ -4,12 +4,13 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import add_days, getdate, cint, cstr
from frappe.utils import add_days, getdate, cint, cstr, date_diff, formatdate
from frappe import throw, _
from erpnext.utilities.transaction_base import TransactionBase, delete_events
from erpnext.stock.utils import get_valid_serial_nos
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
class MaintenanceSchedule(TransactionBase):
@frappe.whitelist()
@ -32,8 +33,40 @@ class MaintenanceSchedule(TransactionBase):
child.idx = count
count = count + 1
child.sales_person = d.sales_person
child.completion_status = "Pending"
child.item_reference = d.name
@frappe.whitelist()
def validate_end_date_visits(self):
days_in_period = {
"Weekly": 7,
"Monthly": 30,
"Quarterly": 91,
"Half Yearly": 182,
"Yearly": 365
}
for item in self.items:
if item.periodicity and item.start_date:
if not item.end_date:
if item.no_of_visits:
item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity])
else:
item.end_date = add_days(item.start_date, days_in_period[item.periodicity])
diff = date_diff(item.end_date, item.start_date) + 1
no_of_visits = cint(diff / days_in_period[item.periodicity])
if not item.no_of_visits or item.no_of_visits == 0:
item.end_date = add_days(item.start_date, days_in_period[item.periodicity])
diff = date_diff(item.end_date, item.start_date) + 1
item.no_of_visits = cint(diff / days_in_period[item.periodicity])
elif item.no_of_visits > no_of_visits:
item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity])
elif item.no_of_visits < no_of_visits:
item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity])
self.save()
def on_submit(self):
if not self.get('schedules'):
@ -58,9 +91,10 @@ class MaintenanceSchedule(TransactionBase):
if no_email_sp:
frappe.msgprint(
frappe._("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format(
_("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format(
self.owner, "<br>" + "<br>".join(no_email_sp)
))
)
)
scheduled_date = frappe.db.sql("""select scheduled_date from
`tabMaintenance Schedule Detail` where sales_person=%s and item_code=%s and
@ -106,7 +140,7 @@ class MaintenanceSchedule(TransactionBase):
if employee:
holiday_list = get_holiday_list_for_employee(employee)
else:
holiday_list = frappe.get_cached_value('Company', self.company, "default_holiday_list")
holiday_list = frappe.get_cached_value('Company', self.company, "default_holiday_list")
holidays = frappe.db.sql_list('''select holiday_date from `tabHoliday` where parent=%s''', holiday_list)
@ -135,8 +169,7 @@ class MaintenanceSchedule(TransactionBase):
}
if date_diff < days_in_period[d.periodicity]:
throw(_("Row {0}: To set {1} periodicity, difference between from and to date \
must be greater than or equal to {2}")
throw(_("Row {0}: To set {1} periodicity, difference between from and to date must be greater than or equal to {2}")
.format(d.idx, d.periodicity, days_in_period[d.periodicity]))
def validate_maintenance_detail(self):
@ -166,13 +199,15 @@ class MaintenanceSchedule(TransactionBase):
throw(_("Maintenance Schedule {0} exists against {1}").format(chk[0][0], d.sales_order))
def validate(self):
self.validate_end_date_visits()
self.validate_maintenance_detail()
self.validate_dates_with_periodicity()
self.validate_sales_order()
self.generate_schedule()
def on_update(self):
frappe.db.set(self, 'status', 'Draft')
def update_amc_date(self, serial_nos, amc_expiry_date=None):
for serial_no in serial_nos:
serial_no_doc = frappe.get_doc("Serial No", serial_no)
@ -202,8 +237,8 @@ class MaintenanceSchedule(TransactionBase):
if not sr_details.warehouse and sr_details.delivery_date and \
getdate(sr_details.delivery_date) >= getdate(amc_start_date):
throw(_("Maintenance start date can not be before delivery date for Serial No {0}")
.format(serial_no))
throw(_("Maintenance start date can not be before delivery date for Serial No {0}")
.format(serial_no))
def validate_schedule(self):
item_lst1 =[]
@ -245,13 +280,50 @@ class MaintenanceSchedule(TransactionBase):
def on_trash(self):
delete_events(self.doctype, self.name)
@frappe.whitelist()
def get_pending_data(self, data_type, s_date=None, item_name=None):
if data_type == "date":
dates = ""
for schedule in self.schedules:
if schedule.item_name == item_name and schedule.completion_status == "Pending":
dates = dates + "\n" + formatdate(schedule.scheduled_date, "dd-MM-yyyy")
return dates
elif data_type == "items":
items = ""
for item in self.items:
for schedule in self.schedules:
if item.item_name == schedule.item_name and schedule.completion_status == "Pending":
items = items + "\n" + item.item_name
break
return items
elif data_type == "id":
for schedule in self.schedules:
if schedule.item_name == item_name and s_date == formatdate(schedule.scheduled_date, "dd-mm-yyyy"):
return schedule.name
@frappe.whitelist()
def make_maintenance_visit(source_name, target_doc=None):
def update_serial_nos(s_id):
serial_nos = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'serial_no')
if serial_nos:
serial_nos = get_serial_nos(serial_nos)
return serial_nos
else:
return False
@frappe.whitelist()
def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=None):
from frappe.model.mapper import get_mapped_doc
def update_status(source, target, parent):
def update_status_and_detail(source, target, parent):
target.maintenance_type = "Scheduled"
target.maintenance_schedule = source.name
target.maintenance_schedule_detail = s_id
def update_sales(source, target, parent):
sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person')
target.service_person = sales_person
target.serial_no = ''
doclist = get_mapped_doc("Maintenance Schedule", source_name, {
"Maintenance Schedule": {
"doctype": "Maintenance Visit",
@ -261,15 +333,12 @@ def make_maintenance_visit(source_name, target_doc=None):
"validation": {
"docstatus": ["=", 1]
},
"postprocess": update_status
"postprocess": update_status_and_detail
},
"Maintenance Schedule Item": {
"doctype": "Maintenance Visit Purpose",
"field_map": {
"parent": "prevdoc_docname",
"parenttype": "prevdoc_doctype",
"sales_person": "service_person"
}
"condition": lambda doc: doc.item_name == item_name,
"postprocess": update_sales
}
}, target_doc)

View File

@ -2,7 +2,8 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
from frappe.utils.data import get_datetime, add_days
from frappe.utils.data import add_days, today, formatdate
from erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule import make_maintenance_visit
import frappe
import unittest
@ -21,7 +22,57 @@ class TestMaintenanceSchedule(unittest.TestCase):
ms.cancel()
events_after_cancel = get_events(ms)
self.assertTrue(len(events_after_cancel) == 0)
def test_make_schedule(self):
ms = make_maintenance_schedule()
ms.save()
i = ms.items[0]
expected_dates = []
expected_end_date = add_days(i.start_date, i.no_of_visits * 7)
self.assertEqual(i.end_date, expected_end_date)
i.no_of_visits = 2
ms.save()
expected_end_date = add_days(i.start_date, i.no_of_visits * 7)
self.assertEqual(i.end_date, expected_end_date)
items = ms.get_pending_data(data_type = "items")
items = items.split('\n')
items.pop(0)
expected_items = ['_Test Item']
self.assertTrue(items, expected_items)
# "dates" contains all generated schedule dates
dates = ms.get_pending_data(data_type = "date", item_name = i.item_name)
dates = dates.split('\n')
dates.pop(0)
expected_dates.append(formatdate(add_days(i.start_date, 7), "dd-MM-yyyy"))
expected_dates.append(formatdate(add_days(i.start_date, 14), "dd-MM-yyyy"))
# test for generated schedule dates
self.assertEqual(dates, expected_dates)
ms.submit()
s_id = ms.get_pending_data(data_type = "id", item_name = i.item_name, s_date = expected_dates[1])
test = make_maintenance_visit(source_name = ms.name, item_name = "_Test Item", s_id = s_id)
visit = frappe.new_doc('Maintenance Visit')
visit = test
visit.maintenance_schedule = ms.name
visit.maintenance_schedule_detail = s_id
visit.completion_status = "Partially Completed"
visit.set('purposes', [{
'item_code': i.item_code,
'description': "test",
'work_done': "test",
'service_person': "Sales Team",
}])
visit.save()
visit.submit()
ms = frappe.get_doc('Maintenance Schedule', ms.name)
#checks if visit status is back updated in schedule
self.assertTrue(ms.schedules[1].completion_status, "Partially Completed")
def get_events(ms):
return frappe.get_all("Event Participants", filters={
"reference_doctype": ms.doctype,
@ -33,12 +84,11 @@ def make_maintenance_schedule():
ms = frappe.new_doc("Maintenance Schedule")
ms.company = "_Test Company"
ms.customer = "_Test Customer"
ms.transaction_date = get_datetime()
ms.transaction_date = today()
ms.append("items", {
"item_code": "_Test Item",
"start_date": get_datetime(),
"end_date": add_days(get_datetime(), 32),
"start_date": today(),
"periodicity": "Weekly",
"no_of_visits": 4,
"sales_person": "Sales Team",

View File

@ -1,222 +1,137 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
"beta": 0,
"creation": "2013-02-22 01:28:05",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"autoname": "hash",
"creation": "2013-02-22 01:28:05",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"item_code",
"item_name",
"column_break_3",
"scheduled_date",
"actual_date",
"section_break_6",
"sales_person",
"column_break_8",
"completion_status",
"section_break_10",
"serial_no",
"item_reference"
],
"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": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Code",
"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": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
"columns": 2,
"fieldname": "item_code",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item Code",
"oldfieldname": "item_code",
"oldfieldtype": "Link",
"options": "Item",
"read_only": 1,
"search_index": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_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": "Item Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"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": "item_name",
"fieldtype": "Data",
"in_global_search": 1,
"label": "Item Name",
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"read_only": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "scheduled_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": "Scheduled Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "scheduled_date",
"oldfieldtype": "Date",
"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": 1,
"set_only_once": 0,
"unique": 0
},
"columns": 2,
"fieldname": "scheduled_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Scheduled Date",
"oldfieldname": "scheduled_date",
"oldfieldtype": "Date",
"reqd": 1,
"search_index": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "actual_date",
"fieldtype": "Date",
"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": "Actual Date",
"length": 0,
"no_copy": 1,
"oldfieldname": "actual_date",
"oldfieldtype": "Date",
"permlevel": 0,
"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
},
"fieldname": "actual_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Actual Date",
"no_copy": 1,
"oldfieldname": "actual_date",
"oldfieldtype": "Date",
"print_hide": 1,
"read_only": 1,
"report_hide": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sales_person",
"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": "Sales Person",
"length": 0,
"no_copy": 0,
"oldfieldname": "incharge_name",
"oldfieldtype": "Link",
"options": "Sales Person",
"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
},
"allow_on_submit": 1,
"columns": 2,
"fieldname": "sales_person",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Sales Person",
"oldfieldname": "incharge_name",
"oldfieldtype": "Link",
"options": "Sales Person",
"read_only_depends_on": "eval:doc.completion_status != \"Pending\""
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "serial_no",
"fieldtype": "Small Text",
"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": "Serial No",
"length": 0,
"no_copy": 0,
"oldfieldname": "serial_no",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "160px",
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "serial_no",
"fieldtype": "Small Text",
"in_list_view": 1,
"label": "Serial No",
"oldfieldname": "serial_no",
"oldfieldtype": "Small Text",
"print_width": "160px",
"read_only": 1,
"width": "160px"
},
{
"columns": 2,
"fieldname": "completion_status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Completion Status",
"options": "Pending\nPartially Completed\nFully Completed",
"read_only": 1
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_6",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_8",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_10",
"fieldtype": "Section Break"
},
{
"fieldname": "item_reference",
"fieldtype": "Link",
"hidden": 1,
"label": "Item Reference",
"options": "Maintenance Schedule Item",
"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-17 17:05:44.644663",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Schedule Detail",
"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": "2021-05-27 16:07:25.905015",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Schedule Detail",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,431 +1,160 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
"beta": 0,
"creation": "2013-02-22 01:28:05",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"autoname": "hash",
"creation": "2013-02-22 01:28:05",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"item_code",
"item_name",
"description",
"column_break_4",
"start_date",
"end_date",
"periodicity",
"schedule_details",
"no_of_visits",
"column_break_10",
"sales_person",
"reference",
"serial_no",
"sales_order"
],
"fields": [
{
"allow_bulk_edit": 0,
"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": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Code",
"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": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"columns": 2,
"fieldname": "item_code",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item Code",
"oldfieldname": "item_code",
"oldfieldtype": "Link",
"options": "Item",
"reqd": 1,
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"columns": 1,
"fetch_from": "item_code.item_name",
"fieldname": "item_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": "Item Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"options": "",
"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,
"translatable": 0,
"unique": 0
},
"fieldname": "item_name",
"fieldtype": "Data",
"in_global_search": 1,
"in_list_view": 1,
"label": "Item Name",
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "item_code.description",
"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": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"oldfieldname": "description",
"oldfieldtype": "Data",
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "300px",
"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": "description",
"fieldtype": "Text Editor",
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Data",
"print_width": "300px",
"read_only": 1,
"width": "300px"
},
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "schedule_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": "",
"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
},
"fieldname": "schedule_details",
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "start_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": "Start Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "start_date",
"oldfieldtype": "Date",
"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": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"columns": 2,
"fieldname": "start_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Start Date",
"oldfieldname": "start_date",
"oldfieldtype": "Date",
"reqd": 1,
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "end_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": "End Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "end_date",
"oldfieldtype": "Date",
"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": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"columns": 2,
"fieldname": "end_date",
"fieldtype": "Date",
"label": "End Date",
"oldfieldname": "end_date",
"oldfieldtype": "Date",
"reqd": 1,
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "periodicity",
"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": "Periodicity",
"length": 0,
"no_copy": 0,
"oldfieldname": "periodicity",
"oldfieldtype": "Select",
"options": "\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly\nRandom",
"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
},
"columns": 1,
"fieldname": "periodicity",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Periodicity",
"oldfieldname": "periodicity",
"oldfieldtype": "Select",
"options": "\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly\nRandom"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "no_of_visits",
"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": "No of Visits",
"length": 0,
"no_copy": 0,
"oldfieldname": "no_of_visits",
"oldfieldtype": "Int",
"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
},
"columns": 1,
"fieldname": "no_of_visits",
"fieldtype": "Int",
"in_list_view": 1,
"label": "No of Visits",
"oldfieldname": "no_of_visits",
"oldfieldtype": "Int",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sales_person",
"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": "Sales Person",
"length": 0,
"no_copy": 0,
"oldfieldname": "incharge_name",
"oldfieldtype": "Link",
"options": "Sales Person",
"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
},
"fieldname": "sales_person",
"fieldtype": "Link",
"label": "Sales Person",
"oldfieldname": "incharge_name",
"oldfieldtype": "Link",
"options": "Sales Person"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference",
"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": "Reference",
"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
},
"fieldname": "reference",
"fieldtype": "Section Break",
"label": "Reference"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "serial_no",
"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": "Serial No",
"length": 0,
"no_copy": 0,
"oldfieldname": "serial_no",
"oldfieldtype": "Small Text",
"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
},
"fieldname": "serial_no",
"fieldtype": "Small Text",
"label": "Serial No",
"oldfieldname": "serial_no",
"oldfieldtype": "Small Text"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sales_order",
"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": "Sales Order",
"length": 0,
"no_copy": 1,
"oldfieldname": "prevdoc_docname",
"oldfieldtype": "Data",
"options": "Sales Order",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"fieldname": "sales_order",
"fieldtype": "Link",
"label": "Sales Order",
"no_copy": 1,
"oldfieldname": "prevdoc_docname",
"oldfieldtype": "Data",
"options": "Sales Order",
"print_hide": 1,
"print_width": "150px",
"read_only": 1,
"search_index": 1,
"width": "150px"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_10",
"fieldtype": "Column Break"
}
],
"has_web_view": 0,
"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": "2018-05-16 22:43:14.260729",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Schedule Item",
"owner": "Administrator",
"permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 0,
"track_seen": 0
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-04-15 16:09:47.311994",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Schedule Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -2,39 +2,62 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.maintenance");
var serial_nos = [];
frappe.ui.form.on('Maintenance Visit', {
refresh: function(frm) {
refresh: function (frm) {
//filters for serial_no based on item_code
frm.set_query('serial_no', 'purposes', function(frm, cdt, cdn) {
frm.set_query('serial_no', 'purposes', function (frm, cdt, cdn) {
let item = locals[cdt][cdn];
return {
filters: {
'item_code': item.item_code
}
};
if (serial_nos) {
return {
filters: {
'item_code': item.item_code,
'name': ["in", serial_nos]
}
};
} else {
return {
filters: {
'item_code': item.item_code
}
};
}
});
},
setup: function(frm) {
setup: function (frm) {
frm.set_query('contact_person', erpnext.queries.contact_query);
frm.set_query('customer_address', erpnext.queries.address_query);
frm.set_query('customer', erpnext.queries.customer);
},
onload: function(frm) {
onload: function (frm, cdt, cdn) {
let item = locals[cdt][cdn];
if (frm.maintenance_type == 'Scheduled') {
let schedule_id = item.purposes[0].prevdoc_detail_docname;
frappe.call({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos",
args: {
s_id: schedule_id
},
callback: function (r) {
serial_nos = r.message;
}
});
}
if (!frm.doc.status) {
frm.set_value({status:'Draft'});
frm.set_value({ status: 'Draft' });
}
if (frm.doc.__islocal) {
frm.set_value({mntc_date: frappe.datetime.get_today()});
frm.set_value({ mntc_date: frappe.datetime.get_today() });
}
},
customer: function(frm) {
customer: function (frm) {
erpnext.utils.get_party_details(frm);
},
customer_address: function(frm) {
customer_address: function (frm) {
erpnext.utils.get_address_display(frm, 'customer_address', 'address_display');
},
contact_person: function(frm) {
contact_person: function (frm) {
erpnext.utils.get_contact_details(frm);
}
@ -42,14 +65,14 @@ frappe.ui.form.on('Maintenance Visit', {
// TODO commonify this code
erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
refresh: function() {
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
refresh: function () {
frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer' };
var me = this;
if (this.frm.doc.docstatus===0) {
if (this.frm.doc.docstatus === 0) {
this.frm.add_custom_button(__('Maintenance Schedule'),
function() {
function () {
erpnext.utils.map_current_doc({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
source_doctype: "Maintenance Schedule",
@ -64,7 +87,7 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
})
}, __("Get Items From"));
this.frm.add_custom_button(__('Warranty Claim'),
function() {
function () {
erpnext.utils.map_current_doc({
method: "erpnext.support.doctype.warranty_claim.warranty_claim.make_maintenance_visit",
source_doctype: "Warranty Claim",
@ -80,7 +103,7 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
})
}, __("Get Items From"));
this.frm.add_custom_button(__('Sales Order'),
function() {
function () {
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
source_doctype: "Sales Order",
@ -99,4 +122,4 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
},
});
$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({ frm: cur_frm }));

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import get_datetime
from erpnext.utilities.transaction_base import TransactionBase
@ -16,44 +17,62 @@ class MaintenanceVisit(TransactionBase):
if d.serial_no and not frappe.db.exists("Serial No", d.serial_no):
frappe.throw(_("Serial No {0} does not exist").format(d.serial_no))
def validate_maintenance_date(self):
if self.maintenance_type == "Scheduled" and self.maintenance_schedule_detail:
item_ref = frappe.db.get_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'item_reference')
if item_ref:
start_date, end_date = frappe.db.get_value('Maintenance Schedule Item', item_ref, ['start_date', 'end_date'])
if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(self.mntc_date) > get_datetime(end_date):
frappe.throw(_("Date must be between {0} and {1}").format(start_date, end_date))
def validate(self):
self.validate_serial_no()
self.validate_maintenance_date()
def update_completion_status(self):
if self.maintenance_schedule_detail:
frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'completion_status', self.completion_status)
def update_actual_date(self):
if self.maintenance_schedule_detail:
frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'actual_date', self.mntc_date)
def update_customer_issue(self, flag):
for d in self.get('purposes'):
if d.prevdoc_docname and d.prevdoc_doctype == 'Warranty Claim' :
if flag==1:
mntc_date = self.mntc_date
service_person = d.service_person
work_done = d.work_done
status = "Open"
if self.completion_status == 'Fully Completed':
status = 'Closed'
elif self.completion_status == 'Partially Completed':
status = 'Work In Progress'
else:
nm = frappe.db.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.name))
if nm:
status = 'Work In Progress'
mntc_date = nm and nm[0][1] or ''
service_person = nm and nm[0][2] or ''
work_done = nm and nm[0][3] or ''
if not self.maintenance_schedule:
for d in self.get('purposes'):
if d.prevdoc_docname and d.prevdoc_doctype == 'Warranty Claim' :
if flag==1:
mntc_date = self.mntc_date
service_person = d.service_person
work_done = d.work_done
status = "Open"
if self.completion_status == 'Fully Completed':
status = 'Closed'
elif self.completion_status == 'Partially Completed':
status = 'Work In Progress'
else:
status = 'Open'
mntc_date = None
service_person = None
work_done = None
nm = frappe.db.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.name))
wc_doc = frappe.get_doc('Warranty Claim', d.prevdoc_docname)
wc_doc.update({
'resolution_date': mntc_date,
'resolved_by': service_person,
'resolution_details': work_done,
'status': status
})
if nm:
status = 'Work In Progress'
mntc_date = nm and nm[0][1] or ''
service_person = nm and nm[0][2] or ''
work_done = nm and nm[0][3] or ''
else:
status = 'Open'
mntc_date = None
service_person = None
work_done = None
wc_doc.db_update()
wc_doc = frappe.get_doc('Warranty Claim', d.prevdoc_docname)
wc_doc.update({
'resolution_date': mntc_date,
'resolved_by': service_person,
'resolution_details': work_done,
'status': status
})
wc_doc.db_update()
def check_if_last_visit(self):
"""check if last maintenance visit against same sales order/ Warranty Claim"""
@ -77,6 +96,8 @@ class MaintenanceVisit(TransactionBase):
def on_submit(self):
self.update_customer_issue(1)
frappe.db.set(self, 'status', 'Submitted')
self.update_completion_status()
self.update_actual_date()
def on_cancel(self):
self.check_if_last_visit()

View File

@ -1,4 +1,5 @@
{
"actions": [],
"autoname": "hash",
"creation": "2013-02-22 01:28:06",
"doctype": "DocType",
@ -8,14 +9,15 @@
"field_order": [
"item_code",
"item_name",
"column_break_3",
"service_person",
"serial_no",
"section_break_6",
"description",
"work_details",
"service_person",
"work_done",
"prevdoc_doctype",
"prevdoc_docname",
"prevdoc_detail_docname"
"prevdoc_docname"
],
"fields": [
{
@ -62,6 +64,8 @@
"fieldtype": "Section Break"
},
{
"fetch_from": "prevdoc_detail_docname.sales_person",
"fetch_if_empty": 1,
"fieldname": "service_person",
"fieldtype": "Link",
"in_list_view": 1,
@ -83,49 +87,30 @@
{
"fieldname": "prevdoc_doctype",
"fieldtype": "Link",
"hidden": 1,
"label": "Document Type",
"no_copy": 1,
"oldfieldname": "prevdoc_doctype",
"oldfieldtype": "Data",
"options": "DocType",
"print_hide": 1,
"print_width": "150px",
"read_only": 1,
"report_hide": 1,
"width": "150px"
"options": "DocType"
},
{
"fieldname": "prevdoc_docname",
"fieldtype": "Dynamic Link",
"hidden": 1,
"label": "Against Document No",
"no_copy": 1,
"oldfieldname": "prevdoc_docname",
"oldfieldtype": "Data",
"options": "prevdoc_doctype",
"print_hide": 1,
"print_width": "160px",
"read_only": 1,
"report_hide": 1,
"width": "160px"
"options": "prevdoc_doctype"
},
{
"fieldname": "prevdoc_detail_docname",
"fieldtype": "Data",
"hidden": 1,
"label": "Against Document Detail No",
"no_copy": 1,
"oldfieldname": "prevdoc_detail_docname",
"oldfieldtype": "Data",
"print_hide": 1,
"print_width": "160px",
"read_only": 1,
"report_hide": 1,
"width": "160px"
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_6",
"fieldtype": "Section Break"
}
],
"idx": 1,
"istable": 1,
"modified": "2020-09-18 17:26:09.703215",
"links": [],
"modified": "2021-05-27 17:47:21.474282",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Visit Purpose",