refactor: serial and batch bundle for Maintenance Schedule
This commit is contained in:
parent
e50e5cc7b1
commit
ba6e1447ef
@ -7,6 +7,19 @@ frappe.ui.form.on('Maintenance Schedule', {
|
||||
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.set_query('serial_and_batch_bundle', 'items', (doc, cdt, cdn) => {
|
||||
let item = locals[cdt][cdn];
|
||||
|
||||
return {
|
||||
filters: {
|
||||
'item_code': item.item_code,
|
||||
'voucher_type': 'Maintenance Schedule',
|
||||
'type_of_transaction': 'Maintenance',
|
||||
'company': doc.company,
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
onload: function (frm) {
|
||||
if (!frm.doc.status) {
|
||||
|
@ -7,7 +7,6 @@ from frappe.utils import add_days, cint, cstr, date_diff, formatdate, getdate
|
||||
|
||||
from erpnext.setup.doctype.employee.employee import get_holiday_list_for_employee
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
from erpnext.stock.utils import get_valid_serial_nos
|
||||
from erpnext.utilities.transaction_base import TransactionBase, delete_events
|
||||
|
||||
|
||||
@ -74,10 +73,14 @@ class MaintenanceSchedule(TransactionBase):
|
||||
|
||||
email_map = {}
|
||||
for d in self.get("items"):
|
||||
if d.serial_no:
|
||||
serial_nos = get_valid_serial_nos(d.serial_no)
|
||||
self.validate_serial_no(d.item_code, serial_nos, d.start_date)
|
||||
self.update_amc_date(serial_nos, d.end_date)
|
||||
if d.serial_and_batch_bundle:
|
||||
serial_nos = frappe.get_doc(
|
||||
"Serial and Batch Bundle", d.serial_and_batch_bundle
|
||||
).get_serial_nos()
|
||||
|
||||
if serial_nos:
|
||||
self.validate_serial_no(d.item_code, serial_nos, d.start_date)
|
||||
self.update_amc_date(serial_nos, d.end_date)
|
||||
|
||||
no_email_sp = []
|
||||
if d.sales_person not in email_map:
|
||||
@ -241,9 +244,27 @@ class MaintenanceSchedule(TransactionBase):
|
||||
self.validate_maintenance_detail()
|
||||
self.validate_dates_with_periodicity()
|
||||
self.validate_sales_order()
|
||||
self.validate_serial_no_bundle()
|
||||
if not self.schedules or self.validate_items_table_change() or self.validate_no_of_visits():
|
||||
self.generate_schedule()
|
||||
|
||||
def validate_serial_no_bundle(self):
|
||||
ids = [d.serial_and_batch_bundle for d in self.items if d.serial_and_batch_bundle]
|
||||
|
||||
if not ids:
|
||||
return
|
||||
|
||||
voucher_nos = frappe.get_all(
|
||||
"Serial and Batch Bundle", fields=["name", "voucher_type"], filters={"name": ("in", ids)}
|
||||
)
|
||||
|
||||
for row in voucher_nos:
|
||||
if row.voucher_type != "Maintenance Schedule":
|
||||
msg = f"""Serial and Batch Bundle {row.name}
|
||||
should have voucher type as 'Maintenance Schedule'"""
|
||||
|
||||
frappe.throw(_(msg))
|
||||
|
||||
def on_update(self):
|
||||
self.db_set("status", "Draft")
|
||||
|
||||
@ -341,9 +362,14 @@ class MaintenanceSchedule(TransactionBase):
|
||||
|
||||
def on_cancel(self):
|
||||
for d in self.get("items"):
|
||||
if d.serial_no:
|
||||
serial_nos = get_valid_serial_nos(d.serial_no)
|
||||
self.update_amc_date(serial_nos)
|
||||
if d.serial_and_batch_bundle:
|
||||
serial_nos = frappe.get_doc(
|
||||
"Serial and Batch Bundle", d.serial_and_batch_bundle
|
||||
).get_serial_nos()
|
||||
|
||||
if serial_nos:
|
||||
self.update_amc_date(serial_nos)
|
||||
|
||||
self.db_set("status", "Cancelled")
|
||||
delete_events(self.doctype, self.name)
|
||||
|
||||
@ -397,11 +423,15 @@ def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=No
|
||||
target.maintenance_schedule_detail = s_id
|
||||
|
||||
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]
|
||||
else:
|
||||
target.serial_no = ""
|
||||
if source.serial_and_batch_bundle:
|
||||
serial_nos = frappe.get_doc(
|
||||
"Serial and Batch Bundle", source.serial_and_batch_bundle
|
||||
).get_serial_nos()
|
||||
|
||||
if len(serial_nos) == 1:
|
||||
target.serial_no = serial_nos[0]
|
||||
else:
|
||||
target.serial_no = ""
|
||||
|
||||
doclist = get_mapped_doc(
|
||||
"Maintenance Schedule",
|
||||
|
@ -20,7 +20,9 @@
|
||||
"sales_person",
|
||||
"reference",
|
||||
"serial_no",
|
||||
"sales_order"
|
||||
"sales_order",
|
||||
"column_break_ugqr",
|
||||
"serial_and_batch_bundle"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -121,7 +123,8 @@
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Serial No",
|
||||
"oldfieldname": "serial_no",
|
||||
"oldfieldtype": "Small Text"
|
||||
"oldfieldtype": "Small Text",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "sales_order",
|
||||
@ -144,17 +147,31 @@
|
||||
{
|
||||
"fieldname": "column_break_10",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_ugqr",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "serial_and_batch_bundle",
|
||||
"fieldtype": "Link",
|
||||
"label": "Serial and Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-04-15 16:09:47.311994",
|
||||
"modified": "2023-03-22 18:44:36.816037",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Maintenance",
|
||||
"name": "Maintenance Schedule Item",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
@ -177,14 +177,14 @@
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Warehouse",
|
||||
"options": "Warehouse",
|
||||
"reqd": 1
|
||||
"mandatory_depends_on": "eval:doc.type_of_transaction != \"Maintenance\"",
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
"fieldname": "type_of_transaction",
|
||||
"fieldtype": "Select",
|
||||
"label": "Type of Transaction",
|
||||
"options": "\nInward\nOutward",
|
||||
"options": "\nInward\nOutward\nMaintenance",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@ -237,7 +237,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-03-21 10:52:25.105421",
|
||||
"modified": "2023-03-22 18:56:37.035516",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial and Batch Bundle",
|
||||
|
@ -8,7 +8,7 @@ import frappe
|
||||
from frappe import _, bold
|
||||
from frappe.model.document import Document
|
||||
from frappe.query_builder.functions import CombineDatetime, Sum
|
||||
from frappe.utils import cint, flt, get_link_to_form, today
|
||||
from frappe.utils import add_days, cint, flt, get_link_to_form, today
|
||||
from pypika import Case
|
||||
|
||||
from erpnext.stock.serial_batch_bundle import BatchNoBundleValuation, SerialNoBundleValuation
|
||||
@ -22,11 +22,14 @@ class SerialandBatchBundle(Document):
|
||||
def validate(self):
|
||||
self.validate_serial_and_batch_no()
|
||||
self.validate_duplicate_serial_and_batch_no()
|
||||
# self.validate_voucher_no()
|
||||
self.check_future_entries_exists()
|
||||
self.validate_serial_nos_inventory()
|
||||
self.validate_voucher_no()
|
||||
|
||||
def before_save(self):
|
||||
if self.type_of_transaction == "Maintenance":
|
||||
return
|
||||
|
||||
self.check_future_entries_exists()
|
||||
self.validate_serial_nos_inventory()
|
||||
self.set_is_outward()
|
||||
self.calculate_qty_and_amount()
|
||||
self.set_warehouse()
|
||||
@ -97,7 +100,7 @@ class SerialandBatchBundle(Document):
|
||||
d.incoming_rate = abs(sn_obj.serial_no_incoming_rate.get(d.serial_no, 0.0))
|
||||
else:
|
||||
d.incoming_rate = abs(sn_obj.batch_avg_rate.get(d.batch_no))
|
||||
available_qty = sn_obj.batch_available_qty.get(d.batch_no) + d.qty
|
||||
available_qty = flt(sn_obj.batch_available_qty.get(d.batch_no)) + flt(d.qty)
|
||||
|
||||
self.validate_negative_batch(d.batch_no, available_qty)
|
||||
|
||||
@ -184,35 +187,37 @@ class SerialandBatchBundle(Document):
|
||||
self.set_incoming_rate(save=True, row=row)
|
||||
self.calculate_qty_and_amount(save=True)
|
||||
self.validate_quantity(row)
|
||||
self.set_warranty_expiry_date(row)
|
||||
|
||||
def validate_voucher_no(self):
|
||||
if self.is_new():
|
||||
def set_warranty_expiry_date(self):
|
||||
if not (self.docstatus == 1 and self.voucher_type == "Delivery Note" and self.has_serial_no):
|
||||
return
|
||||
|
||||
warranty_period = frappe.get_cached_value("Item", self.item_code, "warranty_period")
|
||||
|
||||
if not warranty_period:
|
||||
return
|
||||
|
||||
warranty_expiry_date = add_days(self.posting_date, cint(warranty_period))
|
||||
|
||||
serial_nos = self.get_serial_nos()
|
||||
if not serial_nos:
|
||||
return
|
||||
|
||||
sn_table = frappe.qb.DocType("Serial No")
|
||||
(
|
||||
frappe.qb.update(sn_table)
|
||||
.set(sn_table.warranty_expiry_date, warranty_expiry_date)
|
||||
.where(sn_table.name.isin(serial_nos))
|
||||
).run()
|
||||
|
||||
def validate_voucher_no(self):
|
||||
if not (self.voucher_type and self.voucher_no):
|
||||
return
|
||||
|
||||
if not frappe.db.exists(self.voucher_type, self.voucher_no):
|
||||
if self.voucher_no and not frappe.db.exists(self.voucher_type, self.voucher_no):
|
||||
frappe.throw(_(f"The {self.voucher_type} # {self.voucher_no} does not exist"))
|
||||
|
||||
bundles = frappe.get_all(
|
||||
"Serial and Batch Bundle",
|
||||
filters={
|
||||
"voucher_no": self.voucher_no,
|
||||
"is_cancelled": 0,
|
||||
"name": ["!=", self.name],
|
||||
"item_code": self.item_code,
|
||||
"warehouse": self.warehouse,
|
||||
},
|
||||
)
|
||||
|
||||
if bundles:
|
||||
frappe.throw(
|
||||
_(
|
||||
f"The {self.voucher_type} # {self.voucher_no} already has a Serial and Batch Bundle {bundles[0].name}"
|
||||
)
|
||||
)
|
||||
|
||||
def check_future_entries_exists(self):
|
||||
if not self.has_serial_no:
|
||||
return
|
||||
@ -413,12 +418,6 @@ class SerialandBatchBundle(Document):
|
||||
self.delink_reference_from_batch()
|
||||
self.clear_table()
|
||||
|
||||
def on_update(self):
|
||||
self.validate_negative_stock()
|
||||
|
||||
def validate_negative_stock(self):
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
|
@ -79,12 +79,15 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.item_name",
|
||||
"fetch_if_empty": 1,
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item Name",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.description",
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text",
|
||||
"label": "Description",
|
||||
@ -188,6 +191,7 @@
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.warranty_period",
|
||||
"fieldname": "warranty_period",
|
||||
"fieldtype": "Int",
|
||||
"label": "Warranty Period (Days)",
|
||||
|
@ -385,6 +385,7 @@ class SerialNoBundleValuation(DeprecatedSerialNoValuation):
|
||||
AND child.serial_no IN ({', '.join([frappe.db.escape(s) for s in serial_nos])})
|
||||
AND child.is_outward = 0
|
||||
AND parent.docstatus = 1
|
||||
AND parent.type_of_transaction != 'Maintenance'
|
||||
AND parent.is_cancelled = 0
|
||||
AND child.warehouse = {frappe.db.escape(self.sle.warehouse)}
|
||||
AND parent.item_code = {frappe.db.escape(self.sle.item_code)}
|
||||
@ -521,6 +522,7 @@ class BatchNoBundleValuation(DeprecatedBatchNoValuation):
|
||||
& (parent.item_code == self.sle.item_code)
|
||||
& (parent.docstatus == 1)
|
||||
& (parent.is_cancelled == 0)
|
||||
& (parent.type_of_transaction != "Maintenance")
|
||||
)
|
||||
.where(timestamp_condition)
|
||||
.groupby(child.batch_no)
|
||||
|
Loading…
x
Reference in New Issue
Block a user