refactor: serial no normalization
This commit is contained in:
parent
f11d9b019d
commit
bc75a7ef44
@ -7,7 +7,7 @@ from typing import List, Tuple
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint, cstr, flt, get_link_to_form, getdate
|
||||
from frappe.utils import cint, flt, get_link_to_form, getdate
|
||||
|
||||
import erpnext
|
||||
from erpnext.accounts.general_ledger import (
|
||||
@ -328,26 +328,49 @@ class StockController(AccountsController):
|
||||
def make_batches(self, warehouse_field):
|
||||
"""Create batches if required. Called before submit"""
|
||||
for d in self.items:
|
||||
if d.get(warehouse_field) and not d.batch_no:
|
||||
if d.get(warehouse_field) and not d.serial_and_batch_bundle:
|
||||
has_batch_no, create_new_batch = frappe.get_cached_value(
|
||||
"Item", d.item_code, ["has_batch_no", "create_new_batch"]
|
||||
)
|
||||
|
||||
if has_batch_no and create_new_batch:
|
||||
d.batch_no = (
|
||||
batch_no = (
|
||||
frappe.get_doc(
|
||||
dict(
|
||||
doctype="Batch",
|
||||
item=d.item_code,
|
||||
supplier=getattr(self, "supplier", None),
|
||||
reference_doctype=self.doctype,
|
||||
reference_name=self.name,
|
||||
)
|
||||
dict(doctype="Batch", item=d.item_code, supplier=getattr(self, "supplier", None))
|
||||
)
|
||||
.insert()
|
||||
.name
|
||||
)
|
||||
|
||||
d.serial_and_batch_bundle = (
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Serial and Batch Bundle",
|
||||
"item_code": d.item_code,
|
||||
"voucher_type": self.doctype,
|
||||
"voucher_no": self.name,
|
||||
"ledgers": [
|
||||
{
|
||||
"batch_no": batch_no,
|
||||
"qty": d.qty,
|
||||
"warehouse": d.get(warehouse_field),
|
||||
}
|
||||
],
|
||||
}
|
||||
)
|
||||
.submit()
|
||||
.name
|
||||
)
|
||||
|
||||
frappe.db.set_value(
|
||||
"Batch",
|
||||
batch_no,
|
||||
{
|
||||
"reference_doctype": "Serial and Batch Bundle",
|
||||
"reference_name": d.serial_and_batch_bundle,
|
||||
},
|
||||
)
|
||||
|
||||
def check_expense_account(self, item):
|
||||
if not item.get("expense_account"):
|
||||
msg = _("Please set an Expense Account in the Items table")
|
||||
@ -387,27 +410,20 @@ class StockController(AccountsController):
|
||||
)
|
||||
|
||||
def delete_auto_created_batches(self):
|
||||
for d in self.items:
|
||||
if not d.batch_no:
|
||||
continue
|
||||
|
||||
for row in self.items:
|
||||
if row.serial_and_batch_bundle:
|
||||
frappe.db.set_value(
|
||||
"Serial No", {"batch_no": d.batch_no, "status": "Inactive"}, "batch_no", None
|
||||
"Serial and Batch Bundle", row.serial_and_batch_bundle, {"is_cancelled": 1}
|
||||
)
|
||||
|
||||
d.batch_no = None
|
||||
d.db_set("batch_no", None)
|
||||
|
||||
for data in frappe.get_all(
|
||||
"Batch", {"reference_name": self.name, "reference_doctype": self.doctype}
|
||||
):
|
||||
frappe.delete_doc("Batch", data.name)
|
||||
row.db_set("serial_and_batch_bundle", None)
|
||||
|
||||
def get_sl_entries(self, d, args):
|
||||
sl_dict = frappe._dict(
|
||||
{
|
||||
"item_code": d.get("item_code", None),
|
||||
"warehouse": d.get("warehouse", None),
|
||||
"serial_and_batch_bundle": d.get("serial_and_batch_bundle"),
|
||||
"posting_date": self.posting_date,
|
||||
"posting_time": self.posting_time,
|
||||
"fiscal_year": get_fiscal_year(self.posting_date, company=self.company)[0],
|
||||
@ -420,7 +436,6 @@ class StockController(AccountsController):
|
||||
),
|
||||
"incoming_rate": 0,
|
||||
"company": self.company,
|
||||
"batch_no": cstr(d.get("batch_no")).strip(),
|
||||
"serial_no": d.get("serial_no"),
|
||||
"project": d.get("project") or self.get("project"),
|
||||
"is_cancelled": 1 if self.docstatus == 2 else 0,
|
||||
|
@ -341,9 +341,35 @@ erpnext.buying.BuyingController = class BuyingController extends erpnext.Transac
|
||||
}
|
||||
frappe.throw(msg);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
update_serial_batch_bundle(doc, cdt, cdn) {
|
||||
let item = locals[cdt][cdn];
|
||||
let me = this;
|
||||
let path = "assets/erpnext/js/utils/serial_no_batch_selector.js";
|
||||
|
||||
frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
|
||||
.then((r) => {
|
||||
if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) {
|
||||
item.has_serial_no = r.message.has_serial_no;
|
||||
item.has_batch_no = r.message.has_batch_no;
|
||||
|
||||
frappe.require(path, function() {
|
||||
new erpnext.SerialNoBatchBundleUpdate(
|
||||
me.frm, item, (r) => {
|
||||
if (r) {
|
||||
me.frm.refresh_fields();
|
||||
frappe.model.set_value(cdt, cdn,
|
||||
"serial_and_batch_bundle", r.name);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -119,9 +119,14 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
||||
}
|
||||
});
|
||||
|
||||
if(this.frm.fields_dict["items"].grid.get_field('batch_no')) {
|
||||
this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) {
|
||||
return me.set_query_for_batch(doc, cdt, cdn);
|
||||
if(this.frm.fields_dict["items"].grid.get_field('serial_and_batch_bundle')) {
|
||||
this.frm.set_query("serial_and_batch_bundle", "items", function(doc, cdt, cdn) {
|
||||
let item_row = locals[cdt][cdn];
|
||||
return {
|
||||
filters: {
|
||||
'item_code': item_row.item_code
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -616,3 +616,195 @@ function check_can_calculate_pending_qty(me) {
|
||||
}
|
||||
|
||||
//# sourceURL=serial_no_batch_selector.js
|
||||
|
||||
|
||||
erpnext.SerialNoBatchBundleUpdate = class SerialNoBatchBundleUpdate {
|
||||
constructor(frm, item, callback) {
|
||||
this.frm = frm;
|
||||
this.item = item;
|
||||
this.qty = item.qty;
|
||||
this.callback = callback;
|
||||
this.make();
|
||||
this.render_data();
|
||||
}
|
||||
|
||||
make() {
|
||||
this.dialog = new frappe.ui.Dialog({
|
||||
title: __('Update Serial No / Batch No'),
|
||||
fields: this.get_dialog_fields(),
|
||||
primary_action_label: __('Update'),
|
||||
primary_action: () => this.update_ledgers()
|
||||
});
|
||||
this.dialog.show();
|
||||
}
|
||||
|
||||
get_serial_no_filters() {
|
||||
return {
|
||||
'item_code': this.item.item_code,
|
||||
'warehouse': ["=", ""],
|
||||
'delivery_document_no': ["=", ""],
|
||||
};
|
||||
}
|
||||
|
||||
get_dialog_fields() {
|
||||
let fields = [];
|
||||
|
||||
if (this.item.has_serial_no) {
|
||||
fields.push({
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'scan_serial_no',
|
||||
label: __('Scan Serial No'),
|
||||
options: 'Serial No',
|
||||
get_query: () => {
|
||||
return {
|
||||
filters: this.get_serial_no_filters()
|
||||
};
|
||||
},
|
||||
onchange: () => this.update_serial_batch_no()
|
||||
});
|
||||
}
|
||||
|
||||
if (this.item.has_batch_no && this.item.has_serial_no) {
|
||||
fields.push({
|
||||
fieldtype: 'Column Break',
|
||||
label: __('Batch No')
|
||||
});
|
||||
}
|
||||
|
||||
if (this.item.has_batch_no) {
|
||||
fields.push({
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'scan_batch_no',
|
||||
label: __('Scan Batch No'),
|
||||
options: 'Batch',
|
||||
onchange: () => this.update_serial_batch_no()
|
||||
});
|
||||
}
|
||||
|
||||
if (this.item.has_batch_no && this.item.has_serial_no) {
|
||||
fields.push({
|
||||
fieldtype: 'Section Break',
|
||||
});
|
||||
}
|
||||
|
||||
fields.push({
|
||||
fieldname: 'ledgers',
|
||||
fieldtype: 'Table',
|
||||
allow_bulk_edit: true,
|
||||
data: [],
|
||||
fields: this.get_dialog_table_fields(),
|
||||
});
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
get_dialog_table_fields() {
|
||||
let fields = []
|
||||
|
||||
if (this.item.has_serial_no) {
|
||||
fields.push({
|
||||
fieldtype: 'Link',
|
||||
options: 'Serial No',
|
||||
fieldname: 'serial_no',
|
||||
label: __('Serial No'),
|
||||
in_list_view: 1,
|
||||
get_query: () => {
|
||||
return {
|
||||
filters: this.get_serial_no_filters()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else if (this.item.has_batch_no) {
|
||||
fields = [
|
||||
{
|
||||
fieldtype: 'Link',
|
||||
options: 'Batch',
|
||||
fieldname: 'batch_no',
|
||||
label: __('Batch No'),
|
||||
in_list_view: 1,
|
||||
},
|
||||
{
|
||||
fieldtype: 'Float',
|
||||
fieldname: 'qty',
|
||||
label: __('Quantity'),
|
||||
in_list_view: 1,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
fields.push({
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'name',
|
||||
label: __('Name'),
|
||||
hidden: 1,
|
||||
})
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
update_serial_batch_no() {
|
||||
const { scan_serial_no, scan_batch_no } = this.dialog.get_values();
|
||||
|
||||
if (scan_serial_no) {
|
||||
this.dialog.fields_dict.ledgers.df.data.push({
|
||||
serial_no: scan_serial_no
|
||||
});
|
||||
|
||||
this.dialog.fields_dict.scan_serial_no.set_value('');
|
||||
} else if (scan_batch_no) {
|
||||
this.dialog.fields_dict.ledgers.df.data.push({
|
||||
batch_no: scan_batch_no
|
||||
});
|
||||
|
||||
this.dialog.fields_dict.scan_batch_no.set_value('');
|
||||
}
|
||||
|
||||
this.dialog.fields_dict.ledgers.grid.refresh();
|
||||
}
|
||||
|
||||
update_ledgers() {
|
||||
if (!this.frm.is_new()) {
|
||||
let ledgers = this.dialog.get_values().ledgers;
|
||||
|
||||
if (ledgers && !ledgers.length) {
|
||||
frappe.throw(__('Please add atleast one Serial No / Batch No'));
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.add_serial_batch_no_ledgers',
|
||||
args: {
|
||||
ledgers: ledgers,
|
||||
child_row: this.item
|
||||
}
|
||||
}).then(r => {
|
||||
this.callback && this.callback(r.message);
|
||||
this.dialog.hide();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render_data() {
|
||||
if (!this.frm.is_new() && this.item.serial_and_batch_bundle) {
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.get_serial_batch_no_ledgers',
|
||||
args: {
|
||||
item_code: this.item.item_code,
|
||||
name: this.item.serial_and_batch_bundle,
|
||||
voucher_no: this.item.parent,
|
||||
}
|
||||
}).then(r => {
|
||||
if (r.message) {
|
||||
this.set_data(r.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
set_data(data) {
|
||||
data.forEach(d => {
|
||||
this.dialog.fields_dict.ledgers.df.data.push(d);
|
||||
});
|
||||
|
||||
this.dialog.fields_dict.ledgers.grid.refresh();
|
||||
}
|
||||
}
|
0
erpnext/stock/doctype/package_item/__init__.py
Normal file
0
erpnext/stock/doctype/package_item/__init__.py
Normal file
8
erpnext/stock/doctype/package_item/package_item.js
Normal file
8
erpnext/stock/doctype/package_item/package_item.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Package Item', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
138
erpnext/stock/doctype/package_item/package_item.json
Normal file
138
erpnext/stock/doctype/package_item/package_item.json
Normal file
@ -0,0 +1,138 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2022-09-29 14:56:38.338267",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"item_details_tab",
|
||||
"company",
|
||||
"item_code",
|
||||
"column_break_4",
|
||||
"warehouse",
|
||||
"qty",
|
||||
"serial_no_and_batch_no_tab",
|
||||
"transactions",
|
||||
"reference_details_tab",
|
||||
"voucher_type",
|
||||
"voucher_no",
|
||||
"column_break_12",
|
||||
"voucher_detail_no",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item Code",
|
||||
"options": "Item",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Package Item",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "item_details_tab",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Item Details"
|
||||
},
|
||||
{
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Warehouse",
|
||||
"options": "Warehouse",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Total Qty"
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_details_tab",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Reference Details"
|
||||
},
|
||||
{
|
||||
"fieldname": "voucher_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Voucher Type",
|
||||
"options": "DocType",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "voucher_no",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Voucher No",
|
||||
"options": "voucher_type"
|
||||
},
|
||||
{
|
||||
"fieldname": "voucher_detail_no",
|
||||
"fieldtype": "Data",
|
||||
"label": "Voucher Detail No",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "serial_no_and_batch_no_tab",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Serial No and Batch No"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_12",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "transactions",
|
||||
"fieldtype": "Table",
|
||||
"label": "Items",
|
||||
"options": "Serial and Batch No Transaction",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-10-06 22:07:31.732744",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Package Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
9
erpnext/stock/doctype/package_item/package_item.py
Normal file
9
erpnext/stock/doctype/package_item/package_item.py
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class PackageItem(Document):
|
||||
pass
|
9
erpnext/stock/doctype/package_item/test_package_item.py
Normal file
9
erpnext/stock/doctype/package_item/test_package_item.py
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
|
||||
class TestPackageItem(FrappeTestCase):
|
||||
pass
|
@ -7,6 +7,8 @@ frappe.provide("erpnext.stock");
|
||||
|
||||
frappe.ui.form.on("Purchase Receipt", {
|
||||
setup: (frm) => {
|
||||
frm.ignore_doctypes_on_cancel_all = ['Serial and Batch Bundle'];
|
||||
|
||||
frm.make_methods = {
|
||||
'Landed Cost Voucher': () => {
|
||||
let lcv = frappe.model.get_new_doc('Landed Cost Voucher');
|
||||
|
@ -283,7 +283,12 @@ class PurchaseReceipt(BuyingController):
|
||||
self.update_stock_ledger()
|
||||
self.make_gl_entries_on_cancel()
|
||||
self.repost_future_sle_and_gle()
|
||||
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Repost Item Valuation")
|
||||
self.ignore_linked_doctypes = (
|
||||
"GL Entry",
|
||||
"Stock Ledger Entry",
|
||||
"Repost Item Valuation",
|
||||
"Serial and Batch Bundle",
|
||||
)
|
||||
self.delete_auto_created_batches()
|
||||
self.set_consumed_qty_in_subcontract_order()
|
||||
|
||||
|
@ -91,14 +91,12 @@
|
||||
"delivery_note_item",
|
||||
"putaway_rule",
|
||||
"section_break_45",
|
||||
"allow_zero_valuation_rate",
|
||||
"bom",
|
||||
"serial_no",
|
||||
"update_serial_batch_bundle",
|
||||
"serial_and_batch_bundle",
|
||||
"col_break5",
|
||||
"allow_zero_valuation_rate",
|
||||
"include_exploded_items",
|
||||
"batch_no",
|
||||
"rejected_serial_no",
|
||||
"item_tax_rate",
|
||||
"bom",
|
||||
"item_weight_details",
|
||||
"weight_per_unit",
|
||||
"total_weight",
|
||||
@ -110,6 +108,7 @@
|
||||
"manufacturer_part_no",
|
||||
"accounting_details_section",
|
||||
"expense_account",
|
||||
"item_tax_rate",
|
||||
"column_break_102",
|
||||
"provisional_expense_account",
|
||||
"accounting_dimensions_section",
|
||||
@ -565,37 +564,8 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_45",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.is_fixed_asset",
|
||||
"fieldname": "serial_no",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Serial No",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "serial_no",
|
||||
"oldfieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.is_fixed_asset",
|
||||
"fieldname": "batch_no",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Batch No",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "batch_no",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Batch",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.is_fixed_asset",
|
||||
"fieldname": "rejected_serial_no",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Rejected Serial No",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Serial and Batch No"
|
||||
},
|
||||
{
|
||||
"fieldname": "item_tax_template",
|
||||
@ -1016,12 +986,23 @@
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "serial_and_batch_bundle",
|
||||
"fieldtype": "Link",
|
||||
"label": "Serial and Batch Bundle",
|
||||
"options": "Serial and Batch Bundle"
|
||||
},
|
||||
{
|
||||
"fieldname": "update_serial_batch_bundle",
|
||||
"fieldtype": "Button",
|
||||
"label": "Add Serial / Batch No"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-02-28 15:43:04.470104",
|
||||
"modified": "2023-02-28 16:43:04.470104",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt Item",
|
||||
|
@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Serial and Batch Bundle', {
|
||||
setup(frm) {
|
||||
frm.trigger('set_queries');
|
||||
},
|
||||
|
||||
refresh(frm) {
|
||||
frm.trigger('toggle_fields');
|
||||
},
|
||||
|
||||
set_queries(frm) {
|
||||
frm.set_query('item_code', () => {
|
||||
return {
|
||||
query: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.item_query',
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('voucher_type', () => {
|
||||
return {
|
||||
filters: {
|
||||
'istable': 0,
|
||||
'issingle': 0,
|
||||
'is_submittable': 1,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('voucher_no', () => {
|
||||
return {
|
||||
filters: {
|
||||
'docstatus': ["!=", 2],
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('serial_no', 'ledgers', () => {
|
||||
return {
|
||||
filters: {
|
||||
item_code: frm.doc.item_code,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('batch_no', 'ledgers', () => {
|
||||
return {
|
||||
filters: {
|
||||
item: frm.doc.item_code,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('warehouse', 'ledgers', () => {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
has_serial_no(frm) {
|
||||
frm.trigger('toggle_fields');
|
||||
},
|
||||
|
||||
has_batch_no(frm) {
|
||||
frm.trigger('toggle_fields');
|
||||
},
|
||||
|
||||
toggle_fields(frm) {
|
||||
frm.fields_dict.ledgers.grid.update_docfield_property(
|
||||
'serial_no', 'read_only', !frm.doc.has_serial_no
|
||||
);
|
||||
|
||||
frm.fields_dict.ledgers.grid.update_docfield_property(
|
||||
'batch_no', 'read_only', !frm.doc.has_batch_no
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,162 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2022-09-29 14:56:38.338267",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"item_details_tab",
|
||||
"company",
|
||||
"item_group",
|
||||
"has_serial_no",
|
||||
"column_break_4",
|
||||
"item_code",
|
||||
"item_name",
|
||||
"has_batch_no",
|
||||
"serial_no_and_batch_no_tab",
|
||||
"ledgers",
|
||||
"qty",
|
||||
"tab_break_12",
|
||||
"voucher_type",
|
||||
"voucher_no",
|
||||
"is_cancelled",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "item_details_tab",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Item Details"
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.item_group",
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Link",
|
||||
"label": "Item Group",
|
||||
"options": "Item Group"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fetch_from": "item_code.has_serial_no",
|
||||
"fieldname": "has_serial_no",
|
||||
"fieldtype": "Check",
|
||||
"label": "Has Serial No",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Item Code",
|
||||
"options": "Item",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.item_name",
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item Name"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fetch_from": "item_code.has_batch_no",
|
||||
"fieldname": "has_batch_no",
|
||||
"fieldtype": "Check",
|
||||
"label": "Has Batch No",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "serial_no_and_batch_no_tab",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 1,
|
||||
"fieldname": "ledgers",
|
||||
"fieldtype": "Table",
|
||||
"label": "Serial / Batch Ledgers",
|
||||
"options": "Serial and Batch Ledger",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Total Qty",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "voucher_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Voucher Type",
|
||||
"options": "DocType",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "voucher_no",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Voucher No",
|
||||
"options": "voucher_type"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "is_cancelled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Cancelled",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "tab_break_12",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Reference"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-11-24 13:05:11.623968",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial and Batch Bundle",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "item_code"
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class SerialandBatchBundle(Document):
|
||||
def validate(self):
|
||||
self.validate_serial_and_batch_no()
|
||||
|
||||
def validate_serial_and_batch_no(self):
|
||||
if self.item_code and not self.has_serial_no and not self.has_batch_no:
|
||||
msg = f"The Item {self.item_code} does not have Serial No or Batch No"
|
||||
frappe.throw(_(msg))
|
||||
|
||||
def before_cancel(self):
|
||||
self.delink_serial_and_batch_bundle()
|
||||
self.clear_table()
|
||||
|
||||
def delink_serial_and_batch_bundle(self):
|
||||
self.voucher_no = None
|
||||
|
||||
sles = frappe.get_all("Stock Ledger Entry", filters={"serial_and_batch_bundle": self.name})
|
||||
|
||||
for sle in sles:
|
||||
frappe.db.set_value("Stock Ledger Entry", sle.name, "serial_and_batch_bundle", None)
|
||||
|
||||
def clear_table(self):
|
||||
self.set("ledgers", [])
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@frappe.validate_and_sanitize_search_inputs
|
||||
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
|
||||
item_filters = {"disabled": 0}
|
||||
if txt:
|
||||
item_filters["name"] = ("like", f"%{txt}%")
|
||||
|
||||
return frappe.get_all(
|
||||
"Item",
|
||||
filters=item_filters,
|
||||
or_filters={"has_serial_no": 1, "has_batch_no": 1},
|
||||
fields=["name", "item_name"],
|
||||
as_list=1,
|
||||
)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_serial_batch_no_ledgers(item_code, voucher_no, name=None):
|
||||
return frappe.get_all(
|
||||
"Serial and Batch Bundle",
|
||||
fields=[
|
||||
"`tabSerial and Batch Ledger`.`name`",
|
||||
"`tabSerial and Batch Ledger`.`qty`",
|
||||
"`tabSerial and Batch Ledger`.`warehouse`",
|
||||
"`tabSerial and Batch Ledger`.`batch_no`",
|
||||
"`tabSerial and Batch Ledger`.`serial_no`",
|
||||
],
|
||||
filters=[
|
||||
["Serial and Batch Bundle", "item_code", "=", item_code],
|
||||
["Serial and Batch Ledger", "parent", "=", name],
|
||||
["Serial and Batch Bundle", "voucher_no", "=", voucher_no],
|
||||
["Serial and Batch Bundle", "docstatus", "!=", 2],
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_serial_batch_no_ledgers(ledgers, child_row) -> object:
|
||||
if isinstance(child_row, str):
|
||||
child_row = frappe._dict(frappe.parse_json(child_row))
|
||||
|
||||
if isinstance(ledgers, str):
|
||||
ledgers = frappe.parse_json(ledgers)
|
||||
|
||||
if frappe.db.exists("Serial and Batch Bundle", child_row.serial_and_batch_bundle):
|
||||
doc = update_serial_batch_no_ledgers(ledgers, child_row)
|
||||
else:
|
||||
doc = create_serial_batch_no_ledgers(ledgers, child_row)
|
||||
|
||||
return doc
|
||||
|
||||
|
||||
def create_serial_batch_no_ledgers(ledgers, child_row) -> object:
|
||||
doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Serial and Batch Bundle",
|
||||
"voucher_type": child_row.parenttype,
|
||||
"voucher_no": child_row.parent,
|
||||
"item_code": child_row.item_code,
|
||||
"voucher_detail_no": child_row.name,
|
||||
}
|
||||
)
|
||||
|
||||
for row in ledgers:
|
||||
row = frappe._dict(row)
|
||||
doc.append(
|
||||
"ledgers",
|
||||
{
|
||||
"qty": row.qty or 1.0,
|
||||
"warehouse": child_row.warehouse,
|
||||
"batch_no": row.batch_no,
|
||||
"serial_no": row.serial_no,
|
||||
},
|
||||
)
|
||||
|
||||
doc.save()
|
||||
|
||||
frappe.db.set_value(child_row.doctype, child_row.name, "serial_and_batch_bundle", doc.name)
|
||||
|
||||
frappe.msgprint(_("Serial and Batch Bundle created"), alert=True)
|
||||
|
||||
return doc
|
||||
|
||||
|
||||
def update_serial_batch_no_ledgers(ledgers, child_row) -> object:
|
||||
doc = frappe.get_doc("Serial and Batch Bundle", child_row.serial_and_batch_bundle)
|
||||
doc.voucher_detail_no = child_row.name
|
||||
doc.set("ledgers", [])
|
||||
doc.set("ledgers", ledgers)
|
||||
doc.save()
|
||||
|
||||
frappe.msgprint(_("Serial and Batch Bundle updated"), alert=True)
|
||||
|
||||
return doc
|
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
|
||||
class TestSerialandBatchBundle(FrappeTestCase):
|
||||
pass
|
@ -0,0 +1,73 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2022-09-29 14:55:15.909881",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"serial_no",
|
||||
"batch_no",
|
||||
"column_break_2",
|
||||
"qty",
|
||||
"warehouse",
|
||||
"is_rejected"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"depends_on": "eval:parent.has_serial_no == 1",
|
||||
"fieldname": "serial_no",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Serial No",
|
||||
"mandatory_depends_on": "eval:parent.has_serial_no == 1",
|
||||
"options": "Serial No"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:parent.has_batch_no == 1",
|
||||
"fieldname": "batch_no",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Batch No",
|
||||
"mandatory_depends_on": "eval:parent.has_batch_no == 1",
|
||||
"options": "Batch"
|
||||
},
|
||||
{
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Qty"
|
||||
},
|
||||
{
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Warehouse",
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:parent.voucher_type == 'Purchase Receipt'",
|
||||
"fieldname": "is_rejected",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Rejected"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-11-24 13:00:23.598351",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial and Batch Ledger",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class SerialandBatchLedger(Document):
|
||||
pass
|
@ -189,6 +189,7 @@ class SerialNo(StockController):
|
||||
def get_last_sle(self, serial_no=None):
|
||||
entries = {}
|
||||
sle_dict = self.get_stock_ledger_entries(serial_no)
|
||||
print("sle_dict", sle_dict)
|
||||
if sle_dict:
|
||||
if sle_dict.get("incoming", []):
|
||||
entries["purchase_sle"] = sle_dict["incoming"][0]
|
||||
@ -206,33 +207,23 @@ class SerialNo(StockController):
|
||||
if not serial_no:
|
||||
serial_no = self.name
|
||||
|
||||
print("serial_no", serial_no)
|
||||
for sle in frappe.db.sql(
|
||||
"""
|
||||
SELECT voucher_type, voucher_no,
|
||||
posting_date, posting_time, incoming_rate, actual_qty, serial_no
|
||||
SELECT sle.voucher_type, sle.voucher_no, serial_and_batch_bundle,
|
||||
sle.posting_date, sle.posting_time, sle.incoming_rate, sle.actual_qty, snb.serial_no
|
||||
FROM
|
||||
`tabStock Ledger Entry`
|
||||
`tabStock Ledger Entry` sle, `tabSerial and Batch Ledger` snb
|
||||
WHERE
|
||||
item_code=%s AND company = %s
|
||||
AND is_cancelled = 0
|
||||
AND (serial_no = %s
|
||||
OR serial_no like %s
|
||||
OR serial_no like %s
|
||||
OR serial_no like %s
|
||||
)
|
||||
sle.item_code=%s AND sle.company = %s
|
||||
AND sle.is_cancelled = 0
|
||||
AND snb.serial_no = %s and snb.parent = sle.serial_and_batch_bundle
|
||||
ORDER BY
|
||||
posting_date desc, posting_time desc, creation desc""",
|
||||
(
|
||||
self.item_code,
|
||||
self.company,
|
||||
serial_no,
|
||||
serial_no + "\n%",
|
||||
"%\n" + serial_no,
|
||||
"%\n" + serial_no + "\n%",
|
||||
),
|
||||
sle.posting_date desc, sle.posting_time desc, sle.creation desc""",
|
||||
(self.item_code, self.company, serial_no),
|
||||
as_dict=1,
|
||||
):
|
||||
if serial_no.upper() in get_serial_nos(sle.serial_no):
|
||||
if serial_no.upper() in get_serial_nos(sle.serial_and_batch_bundle):
|
||||
if cint(sle.actual_qty) > 0:
|
||||
sle_dict.setdefault("incoming", []).append(sle)
|
||||
else:
|
||||
@ -262,6 +253,7 @@ class SerialNo(StockController):
|
||||
|
||||
def update_serial_no_reference(self, serial_no=None):
|
||||
last_sle = self.get_last_sle(serial_no)
|
||||
print(last_sle)
|
||||
self.set_purchase_details(last_sle.get("purchase_sle"))
|
||||
self.set_sales_details(last_sle.get("delivery_sle"))
|
||||
self.set_maintenance_status()
|
||||
@ -275,7 +267,7 @@ def process_serial_no(sle):
|
||||
|
||||
|
||||
def validate_serial_no(sle, item_det):
|
||||
serial_nos = get_serial_nos(sle.serial_no) if sle.serial_no else []
|
||||
serial_nos = get_serial_nos(sle.serial_and_batch_bundle) if sle.serial_and_batch_bundle else []
|
||||
validate_material_transfer_entry(sle)
|
||||
|
||||
if item_det.has_serial_no == 0:
|
||||
@ -541,7 +533,7 @@ def update_serial_nos(sle, item_det):
|
||||
return
|
||||
if (
|
||||
not sle.is_cancelled
|
||||
and not sle.serial_no
|
||||
and not sle.serial_and_batch_bundle
|
||||
and cint(sle.actual_qty) > 0
|
||||
and item_det.has_serial_no == 1
|
||||
and item_det.serial_no_series
|
||||
@ -549,7 +541,7 @@ def update_serial_nos(sle, item_det):
|
||||
serial_nos = get_auto_serial_nos(item_det.serial_no_series, sle.actual_qty)
|
||||
sle.db_set("serial_no", serial_nos)
|
||||
validate_serial_no(sle, item_det)
|
||||
if sle.serial_no:
|
||||
if sle.serial_and_batch_bundle:
|
||||
auto_make_serial_nos(sle)
|
||||
|
||||
|
||||
@ -569,7 +561,7 @@ def get_new_serial_number(series):
|
||||
|
||||
|
||||
def auto_make_serial_nos(args):
|
||||
serial_nos = get_serial_nos(args.get("serial_no"))
|
||||
serial_nos = get_serial_nos(args.get("serial_and_batch_bundle"))
|
||||
created_numbers = []
|
||||
voucher_type = args.get("voucher_type")
|
||||
item_code = args.get("item_code")
|
||||
@ -624,13 +616,14 @@ def get_item_details(item_code):
|
||||
)[0]
|
||||
|
||||
|
||||
def get_serial_nos(serial_no):
|
||||
if isinstance(serial_no, list):
|
||||
return serial_no
|
||||
def get_serial_nos(serial_and_batch_bundle):
|
||||
serial_nos = frappe.get_all(
|
||||
"Serial and Batch Ledger",
|
||||
filters={"parent": serial_and_batch_bundle, "serial_no": ("is", "set")},
|
||||
fields=["serial_no"],
|
||||
)
|
||||
|
||||
return [
|
||||
s.strip() for s in cstr(serial_no).strip().upper().replace(",", "\n").split("\n") if s.strip()
|
||||
]
|
||||
return [d.serial_no for d in serial_nos]
|
||||
|
||||
|
||||
def clean_serial_no_string(serial_no: str) -> str:
|
||||
|
@ -31,6 +31,7 @@
|
||||
"company",
|
||||
"stock_uom",
|
||||
"project",
|
||||
"serial_and_batch_bundle",
|
||||
"batch_no",
|
||||
"column_break_26",
|
||||
"fiscal_year",
|
||||
@ -309,6 +310,13 @@
|
||||
"label": "Recalculate Incoming/Outgoing Rate",
|
||||
"no_copy": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "serial_and_batch_bundle",
|
||||
"fieldtype": "Link",
|
||||
"label": "Serial and Batch Bundle",
|
||||
"options": "Serial and Batch Bundle",
|
||||
"search_index": 1
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
@ -317,7 +325,7 @@
|
||||
"in_create": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-12-21 06:25:30.040801",
|
||||
"modified": "2022-11-24 13:14:31.974743",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock Ledger Entry",
|
||||
|
@ -40,7 +40,7 @@ class StockLedgerEntry(Document):
|
||||
from erpnext.stock.utils import validate_disabled_warehouse, validate_warehouse_company
|
||||
|
||||
self.validate_mandatory()
|
||||
self.validate_item()
|
||||
self.validate_serial_batch_no_bundle()
|
||||
self.validate_batch()
|
||||
validate_disabled_warehouse(self.warehouse)
|
||||
validate_warehouse_company(self.warehouse, self.company)
|
||||
@ -79,47 +79,43 @@ class StockLedgerEntry(Document):
|
||||
if self.voucher_type != "Stock Reconciliation" and not self.actual_qty:
|
||||
frappe.throw(_("Actual Qty is mandatory"))
|
||||
|
||||
def validate_item(self):
|
||||
item_det = frappe.db.sql(
|
||||
"""select name, item_name, has_batch_no, docstatus,
|
||||
is_stock_item, has_variants, stock_uom, create_new_batch
|
||||
from tabItem where name=%s""",
|
||||
def validate_serial_batch_no_bundle(self):
|
||||
item_detail = frappe.get_cached_value(
|
||||
"Item",
|
||||
self.item_code,
|
||||
as_dict=True,
|
||||
["has_serial_no", "has_batch_no", "is_stock_item", "has_variants", "stock_uom"],
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
if not item_det:
|
||||
if not item_detail:
|
||||
frappe.throw(_("Item {0} not found").format(self.item_code))
|
||||
|
||||
item_det = item_det[0]
|
||||
|
||||
if item_det.is_stock_item != 1:
|
||||
frappe.throw(_("Item {0} must be a stock Item").format(self.item_code))
|
||||
|
||||
# check if batch number is valid
|
||||
if item_det.has_batch_no == 1:
|
||||
batch_item = (
|
||||
self.item_code
|
||||
if self.item_code == item_det.item_name
|
||||
else self.item_code + ":" + item_det.item_name
|
||||
)
|
||||
if not self.batch_no:
|
||||
frappe.throw(_("Batch number is mandatory for Item {0}").format(batch_item))
|
||||
elif not frappe.db.get_value("Batch", {"item": self.item_code, "name": self.batch_no}):
|
||||
frappe.throw(
|
||||
_("{0} is not a valid Batch Number for Item {1}").format(self.batch_no, batch_item)
|
||||
)
|
||||
|
||||
elif item_det.has_batch_no == 0 and self.batch_no and self.is_cancelled == 0:
|
||||
frappe.throw(_("The Item {0} cannot have Batch").format(self.item_code))
|
||||
|
||||
if item_det.has_variants:
|
||||
if item_detail.has_variants:
|
||||
frappe.throw(
|
||||
_("Stock cannot exist for Item {0} since has variants").format(self.item_code),
|
||||
ItemTemplateCannotHaveStock,
|
||||
)
|
||||
|
||||
self.stock_uom = item_det.stock_uom
|
||||
if item_detail.is_stock_item != 1:
|
||||
frappe.throw(_("Item {0} must be a stock Item").format(self.item_code))
|
||||
|
||||
if item_detail.has_serial_no or item_detail.has_batch_no:
|
||||
if not self.serial_and_batch_bundle:
|
||||
frappe.throw(_(f"Serial No and Batch No are mandatory for Item {self.item_code}"))
|
||||
elif self.item_code != frappe.get_cached_value(
|
||||
"Serial and Batch Bundle", self.serial_and_batch_bundle, "item_code"
|
||||
):
|
||||
frappe.throw(
|
||||
_(
|
||||
f"Serial No and Batch No Bundle {self.serial_and_batch_bundle} is not for Item {self.item_code}"
|
||||
)
|
||||
)
|
||||
|
||||
if self.serial_and_batch_bundle and not (item_detail.has_serial_no or item_detail.has_batch_no):
|
||||
frappe.throw(_(f"Serial No and Batch No are not allowed for Item {self.item_code}"))
|
||||
|
||||
if self.stock_uom != item_detail.stock_uom:
|
||||
self.stock_uom = item_detail.stock_uom
|
||||
|
||||
def check_stock_frozen_date(self):
|
||||
stock_settings = frappe.get_cached_doc("Stock Settings")
|
||||
|
Loading…
x
Reference in New Issue
Block a user