Skip to content

Commit

Permalink
Merge pull request #28843 from noahjacob/maint_sch_link_fix
Browse files Browse the repository at this point in the history
refactor: update_serial_no function for old Maintenance Visits
  • Loading branch information
marination authored Jan 19, 2022
2 parents 34fad75 + dec7513 commit b9f70ed
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt


import frappe
from frappe import _, throw
from frappe.utils import add_days, cint, cstr, date_diff, formatdate, getdate
Expand Down Expand Up @@ -306,26 +305,28 @@ def get_pending_data(self, data_type, s_date=None, item_name=None):
return schedule.name

@frappe.whitelist()
def update_serial_nos(s_id):
serial_nos = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'serial_no')
def get_serial_nos_from_schedule(item_code, schedule=None):
serial_nos = []
if schedule:
serial_nos = frappe.db.get_value('Maintenance Schedule Item', {
'parent': schedule,
'item_code': item_code
}, 'serial_no')

if serial_nos:
serial_nos = get_serial_nos(serial_nos)
return serial_nos
else:
return False

return serial_nos

@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_and_detail(source, target, parent):
target.maintenance_type = "Scheduled"
target.maintenance_schedule = source.name
target.maintenance_schedule_detail = s_id

def update_sales_and_serial(source, target, parent):
sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person')
target.service_person = sales_person
def update_serial(source, target, parent):
serial_nos = get_serial_nos(target.serial_no)
if len(serial_nos) == 1:
target.serial_no = serial_nos[0]
Expand All @@ -346,7 +347,10 @@ def update_sales_and_serial(source, target, parent):
"Maintenance Schedule Item": {
"doctype": "Maintenance Visit Purpose",
"condition": lambda doc: doc.item_name == item_name,
"postprocess": update_sales_and_serial
"field_map": {
"sales_person": "service_person"
},
"postprocess": update_serial
}
}, target_doc)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
from frappe.utils.data import add_days, formatdate, today

from erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule import (
get_serial_nos_from_schedule,
make_maintenance_visit,
)
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item

# test_records = frappe.get_test_records('Maintenance Schedule')

Expand Down Expand Up @@ -80,24 +83,61 @@ def test_make_schedule(self):
#checks if visit status is back updated in schedule
self.assertTrue(ms.schedules[1].completion_status, "Partially Completed")

def test_serial_no_filters(self):
# Without serial no. set in schedule -> returns None
item_code = "_Test Serial Item"
make_serial_item_with_serial(item_code)
ms = make_maintenance_schedule(item_code=item_code)
ms.submit()

s_item = ms.schedules[0]
mv = make_maintenance_visit(source_name=ms.name, item_name=item_code, s_id=s_item.name)
mvi = mv.purposes[0]
serial_nos = get_serial_nos_from_schedule(mvi.item_name, ms.name)
self.assertEqual(serial_nos, None)

# With serial no. set in schedule -> returns serial nos.
make_serial_item_with_serial(item_code)
ms = make_maintenance_schedule(item_code=item_code, serial_no="TEST001, TEST002")
ms.submit()

s_item = ms.schedules[0]
mv = make_maintenance_visit(source_name=ms.name, item_name=item_code, s_id=s_item.name)
mvi = mv.purposes[0]
serial_nos = get_serial_nos_from_schedule(mvi.item_name, ms.name)
self.assertEqual(serial_nos, ["TEST001", "TEST002"])

frappe.db.rollback()

def make_serial_item_with_serial(item_code):
serial_item_doc = create_item(item_code, is_stock_item=1)
if not serial_item_doc.has_serial_no or not serial_item_doc.serial_no_series:
serial_item_doc.has_serial_no = 1
serial_item_doc.serial_no_series = "TEST.###"
serial_item_doc.save(ignore_permissions=True)
active_serials = frappe.db.get_all('Serial No', {"status": "Active", "item_code": item_code})
if len(active_serials) < 2:
make_serialized_item(item_code=item_code)

def get_events(ms):
return frappe.get_all("Event Participants", filters={
"reference_doctype": ms.doctype,
"reference_docname": ms.name,
"parenttype": "Event"
})

def make_maintenance_schedule():
def make_maintenance_schedule(**args):
ms = frappe.new_doc("Maintenance Schedule")
ms.company = "_Test Company"
ms.customer = "_Test Customer"
ms.transaction_date = today()

ms.append("items", {
"item_code": "_Test Item",
"item_code": args.get("item_code") or "_Test Item",
"start_date": today(),
"periodicity": "Weekly",
"no_of_visits": 4,
"serial_no": args.get("serial_no"),
"sales_person": "Sales Team",
})
ms.insert(ignore_permissions=True)
Expand Down
63 changes: 32 additions & 31 deletions erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,54 @@
// 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) {
//filters for serial_no based on item_code
frm.set_query('serial_no', 'purposes', function (frm, cdt, cdn) {
let item = locals[cdt][cdn];
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) {
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, cdt, cdn) {
let item = locals[cdt][cdn];
onload: function (frm) {
// filters for serial no based on item code
if (frm.doc.maintenance_type === "Scheduled") {
const schedule_id = item.purposes[0].prevdoc_detail_docname || frm.doc.maintenance_schedule_detail;
let item_code = frm.doc.purposes[0].item_code;
frappe.call({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos",
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.get_serial_nos_from_schedule",
args: {
s_id: schedule_id
},
callback: function (r) {
serial_nos = r.message;
schedule: frm.doc.maintenance_schedule,
item_code: item_code
}
}).then((r) => {
let serial_nos = r.message;
frm.set_query('serial_no', 'purposes', () => {
if (serial_nos.length > 0) {
return {
filters: {
'item_code': item_code,
'name': ["in", serial_nos]
}
};
}
return {
filters: {
'item_code': item_code
}
};
});
});
} else {
frm.set_query('serial_no', 'purposes', (frm, cdt, cdn) => {
let row = locals[cdt][cdn];
return {
filters: {
'item_code': row.item_code
}
};
});
}
if (!frm.doc.status) {
frm.set_value({ status: 'Draft' });
}
if (frm.doc.__islocal) {
frm.doc.maintenance_type == 'Unscheduled' && frm.clear_table("purposes");
frm.set_value({ mntc_date: frappe.datetime.get_today() });
}
},
Expand All @@ -60,7 +62,6 @@ frappe.ui.form.on('Maintenance Visit', {
contact_person: function (frm) {
erpnext.utils.get_contact_details(frm);
}

})

// TODO commonify this code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@
"label": "Purposes",
"oldfieldname": "maintenance_visit_details",
"oldfieldtype": "Table",
"options": "Maintenance Visit Purpose",
"reqd": 1
"options": "Maintenance Visit Purpose"
},
{
"fieldname": "more_info",
Expand Down Expand Up @@ -294,10 +293,11 @@
"idx": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-05-27 16:06:17.352572",
"modified": "2021-12-17 03:10:27.608112",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Visit",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def validate_serial_no(self):
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_purpose_table(self):
if not self.purposes:
frappe.throw(_("Add Items in the Purpose Table"), title="Purposes Required")

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')
Expand All @@ -29,6 +33,7 @@ def validate_maintenance_date(self):
def validate(self):
self.validate_serial_no()
self.validate_maintenance_date()
self.validate_purpose_table()

def update_completion_status(self):
if self.maintenance_schedule_detail:
Expand Down
1 change: 1 addition & 0 deletions erpnext/patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ erpnext.patches.v14_0.delete_healthcare_doctypes
erpnext.patches.v13_0.update_category_in_ltds_certificate
erpnext.patches.v13_0.create_pan_field_for_india #2
erpnext.patches.v14_0.delete_hub_doctypes
erpnext.patches.v13_0.update_maintenance_schedule_field_in_visit
erpnext.patches.v13_0.create_ksa_vat_custom_fields # 07-01-2022
erpnext.patches.v14_0.rename_ongoing_status_in_sla_documents
erpnext.patches.v14_0.migrate_crm_settings
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

import frappe


def execute():
# Updates the Maintenance Schedule link to fetch serial nos
from frappe.query_builder.functions import Coalesce
mvp = frappe.qb.DocType('Maintenance Visit Purpose')
mv = frappe.qb.DocType('Maintenance Visit')

frappe.qb.update(
mv
).join(
mvp
).on(mvp.parent == mv.name).set(
mv.maintenance_schedule,
Coalesce(mvp.prevdoc_docname, '')
).where(
(mv.maintenance_type == "Scheduled")
& (mvp.prevdoc_docname.notnull())
& (mv.docstatus < 2)
).run(as_dict=1)

0 comments on commit b9f70ed

Please sign in to comment.