mirror of
https://github.com/frappe/erpnext.git
synced 2026-03-29 09:01:14 +02:00
fix: serial and batch no selector (#43387)
(cherry picked from commit e4e96d2a44)
Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
This commit is contained in:
@@ -342,12 +342,15 @@ erpnext.buying = {
|
|||||||
add_serial_batch_bundle(doc, cdt, cdn) {
|
add_serial_batch_bundle(doc, cdt, cdn) {
|
||||||
let item = locals[cdt][cdn];
|
let item = locals[cdt][cdn];
|
||||||
let me = this;
|
let me = this;
|
||||||
|
let fields = ["has_batch_no", "has_serial_no"];
|
||||||
|
|
||||||
frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
|
frappe.db.get_value("Item", item.item_code, fields)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) {
|
if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) {
|
||||||
item.has_serial_no = r.message.has_serial_no;
|
fields.forEach((field) => {
|
||||||
item.has_batch_no = r.message.has_batch_no;
|
item[field] = r.message[field];
|
||||||
|
});
|
||||||
|
|
||||||
item.type_of_transaction = item.qty > 0 ? "Inward" : "Outward";
|
item.type_of_transaction = item.qty > 0 ? "Inward" : "Outward";
|
||||||
item.is_rejected = false;
|
item.is_rejected = false;
|
||||||
|
|
||||||
@@ -380,12 +383,15 @@ erpnext.buying = {
|
|||||||
add_serial_batch_for_rejected_qty(doc, cdt, cdn) {
|
add_serial_batch_for_rejected_qty(doc, cdt, cdn) {
|
||||||
let item = locals[cdt][cdn];
|
let item = locals[cdt][cdn];
|
||||||
let me = this;
|
let me = this;
|
||||||
|
let fields = ["has_batch_no", "has_serial_no"];
|
||||||
|
|
||||||
frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
|
frappe.db.get_value("Item", item.item_code, fields)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) {
|
if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) {
|
||||||
item.has_serial_no = r.message.has_serial_no;
|
fields.forEach((field) => {
|
||||||
item.has_batch_no = r.message.has_batch_no;
|
item[field] = r.message[field];
|
||||||
|
});
|
||||||
|
|
||||||
item.type_of_transaction = item.rejected_qty > 0 ? "Inward" : "Outward";
|
item.type_of_transaction = item.rejected_qty > 0 ? "Inward" : "Outward";
|
||||||
item.is_rejected = true;
|
item.is_rejected = true;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
let label = this.item?.has_serial_no ? __("Serial Nos") : __("Batch Nos");
|
let label = this.item?.has_serial_no ? __("Serial Nos") : __("Batch Nos");
|
||||||
let primary_label = this.bundle ? __("Update") : __("Add");
|
let primary_label = this.bundle ? __("Update") : __("Add");
|
||||||
|
|
||||||
if (this.item?.has_serial_no && this.item?.batch_no) {
|
if (this.item?.has_serial_no && this.item?.has_batch_no) {
|
||||||
label = __("Serial Nos / Batch Nos");
|
label = __("Serial Nos / Batch Nos");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
|
|
||||||
this.dialog = new frappe.ui.Dialog({
|
this.dialog = new frappe.ui.Dialog({
|
||||||
title: this.item?.title || primary_label,
|
title: this.item?.title || primary_label,
|
||||||
|
size: "large",
|
||||||
fields: this.get_dialog_fields(),
|
fields: this.get_dialog_fields(),
|
||||||
primary_action_label: primary_label,
|
primary_action_label: primary_label,
|
||||||
primary_action: () => this.update_bundle_entries(),
|
primary_action: () => this.update_bundle_entries(),
|
||||||
@@ -164,12 +165,14 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
fieldtype: "Section Break",
|
fieldtype: "Section Break",
|
||||||
|
depends_on: "eval:doc.enter_manually !== 1 || doc.entries?.length > 0",
|
||||||
});
|
});
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
fieldname: "entries",
|
fieldname: "entries",
|
||||||
fieldtype: "Table",
|
fieldtype: "Table",
|
||||||
allow_bulk_edit: true,
|
allow_bulk_edit: true,
|
||||||
|
depends_on: "eval:doc.enter_manually !== 1 || doc.entries?.length > 0",
|
||||||
data: [],
|
data: [],
|
||||||
fields: this.get_dialog_table_fields(),
|
fields: this.get_dialog_table_fields(),
|
||||||
});
|
});
|
||||||
@@ -178,6 +181,7 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_attach_field() {
|
get_attach_field() {
|
||||||
|
let me = this;
|
||||||
let label = this.item?.has_serial_no ? __("Serial Nos") : __("Batch Nos");
|
let label = this.item?.has_serial_no ? __("Serial Nos") : __("Batch Nos");
|
||||||
let primary_label = this.bundle ? __("Update") : __("Add");
|
let primary_label = this.bundle ? __("Update") : __("Add");
|
||||||
|
|
||||||
@@ -185,66 +189,41 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
label = __("Serial Nos / Batch Nos");
|
label = __("Serial Nos / Batch Nos");
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = [
|
let fields = [];
|
||||||
{
|
if (this.item.has_serial_no) {
|
||||||
fieldtype: "Section Break",
|
fields.push({
|
||||||
label: __("{0} {1} via CSV File", [primary_label, label]),
|
fieldtype: "Check",
|
||||||
},
|
label: __("Enter Manually"),
|
||||||
];
|
fieldname: "enter_manually",
|
||||||
|
default: 1,
|
||||||
if (this.item?.has_serial_no) {
|
depends_on: "eval:doc.import_using_csv_file !== 1",
|
||||||
fields = [
|
change() {
|
||||||
...fields,
|
if (me.dialog.get_value("enter_manually")) {
|
||||||
{
|
me.dialog.set_value("import_using_csv_file", 0);
|
||||||
fieldtype: "Check",
|
}
|
||||||
label: __("Import Using CSV file"),
|
|
||||||
fieldname: "import_using_csv_file",
|
|
||||||
default: 0,
|
|
||||||
},
|
},
|
||||||
{
|
});
|
||||||
fieldtype: "Section Break",
|
|
||||||
label: __("{0} {1} Manually", [primary_label, label]),
|
|
||||||
depends_on: "eval:doc.import_using_csv_file === 0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: "Data",
|
|
||||||
label: __("Enter Serial No Range"),
|
|
||||||
fieldname: "serial_no_range",
|
|
||||||
depends_on: "eval:doc.import_using_csv_file === 0",
|
|
||||||
description: __('Enter "ABC-001::100" for serial nos "ABC-001" to "ABC-100".'),
|
|
||||||
onchange: () => {
|
|
||||||
this.set_serial_nos_from_range();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: "Small Text",
|
|
||||||
label: __("Enter Serial Nos"),
|
|
||||||
fieldname: "upload_serial_nos",
|
|
||||||
depends_on: "eval:doc.import_using_csv_file === 0",
|
|
||||||
description: __("Enter each serial no in a new line"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: "Column Break",
|
|
||||||
depends_on: "eval:doc.import_using_csv_file === 0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: "Button",
|
|
||||||
fieldname: "make_serial_nos",
|
|
||||||
label: __("Create Serial Nos"),
|
|
||||||
depends_on: "eval:doc.import_using_csv_file === 0",
|
|
||||||
click: () => {
|
|
||||||
this.create_serial_nos();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: "Section Break",
|
|
||||||
depends_on: "eval:doc.import_using_csv_file === 1",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fields = [
|
fields = [
|
||||||
...fields,
|
...fields,
|
||||||
|
{
|
||||||
|
fieldtype: "Check",
|
||||||
|
label: __("Import Using CSV file"),
|
||||||
|
fieldname: "import_using_csv_file",
|
||||||
|
depends_on: "eval:doc.enter_manually !== 1",
|
||||||
|
default: !this.item.has_serial_no ? 1 : 0,
|
||||||
|
change() {
|
||||||
|
if (me.dialog.get_value("import_using_csv_file")) {
|
||||||
|
me.dialog.set_value("enter_manually", 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: "Section Break",
|
||||||
|
depends_on: "eval:doc.import_using_csv_file === 1",
|
||||||
|
label: __("{0} {1} via CSV File", [primary_label, label]),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldtype: "Button",
|
fieldtype: "Button",
|
||||||
fieldname: "download_csv",
|
fieldname: "download_csv",
|
||||||
@@ -262,9 +241,51 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (this.item?.has_serial_no) {
|
||||||
|
fields = [
|
||||||
|
...fields,
|
||||||
|
{
|
||||||
|
fieldtype: "Section Break",
|
||||||
|
label: __("{0} {1} Manually", [primary_label, label]),
|
||||||
|
depends_on: "eval:doc.enter_manually === 1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: "Data",
|
||||||
|
label: __("Serial No Range"),
|
||||||
|
fieldname: "serial_no_range",
|
||||||
|
depends_on: "eval:doc.enter_manually === 1 && !doc.serial_no_series",
|
||||||
|
description: __('"SN-01::10" for "SN-01" to "SN-10"'),
|
||||||
|
onchange: () => {
|
||||||
|
this.set_serial_nos_from_range();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.item?.has_serial_no) {
|
||||||
|
fields = [
|
||||||
|
...fields,
|
||||||
|
{
|
||||||
|
fieldtype: "Column Break",
|
||||||
|
depends_on: "eval:doc.enter_manually === 1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: "Small Text",
|
||||||
|
label: __("Enter Serial Nos"),
|
||||||
|
fieldname: "upload_serial_nos",
|
||||||
|
depends_on: "eval:doc.enter_manually === 1",
|
||||||
|
description: __("Enter each serial no in a new line"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_serial_nos_from_series() {}
|
||||||
|
|
||||||
|
set_batch_nos_from_series() {}
|
||||||
|
|
||||||
set_serial_nos_from_range() {
|
set_serial_nos_from_range() {
|
||||||
const serial_no_range = this.dialog.get_value("serial_no_range");
|
const serial_no_range = this.dialog.get_value("serial_no_range");
|
||||||
|
|
||||||
@@ -511,6 +532,8 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
scan_barcode_data() {
|
scan_barcode_data() {
|
||||||
const { scan_serial_no, scan_batch_no } = this.dialog.get_values();
|
const { scan_serial_no, scan_batch_no } = this.dialog.get_values();
|
||||||
|
|
||||||
|
this.dialog.set_value("enter_manually", 0);
|
||||||
|
|
||||||
if (scan_serial_no || scan_batch_no) {
|
if (scan_serial_no || scan_batch_no) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.is_serial_batch_no_exists",
|
method: "erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.is_serial_batch_no_exists",
|
||||||
@@ -554,14 +577,13 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
serial_no: scan_serial_no,
|
serial_no: scan_serial_no,
|
||||||
},
|
},
|
||||||
callback: (r) => {
|
callback: (r) => {
|
||||||
if (r.message) {
|
this.dialog.fields_dict.entries.df.data.push({
|
||||||
this.dialog.fields_dict.entries.df.data.push({
|
serial_no: scan_serial_no,
|
||||||
serial_no: scan_serial_no,
|
batch_no: r.message,
|
||||||
batch_no: r.message,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
this.dialog.fields_dict.scan_serial_no.set_value("");
|
this.dialog.fields_dict.scan_serial_no.set_value("");
|
||||||
}
|
this.dialog.fields_dict.entries.grid.refresh();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -590,6 +612,12 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
update_bundle_entries() {
|
update_bundle_entries() {
|
||||||
let entries = this.dialog.get_values().entries;
|
let entries = this.dialog.get_values().entries;
|
||||||
let warehouse = this.dialog.get_value("warehouse");
|
let warehouse = this.dialog.get_value("warehouse");
|
||||||
|
let upload_serial_nos = this.dialog.get_value("upload_serial_nos");
|
||||||
|
|
||||||
|
if (!entries?.length && upload_serial_nos) {
|
||||||
|
this.create_serial_nos();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((entries && !entries.length) || !entries) {
|
if ((entries && !entries.length) || !entries) {
|
||||||
frappe.throw(__("Please add atleast one Serial No / Batch No"));
|
frappe.throw(__("Please add atleast one Serial No / Batch No"));
|
||||||
@@ -610,9 +638,13 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
this.callback && this.callback(r.message);
|
frappe.run_serially([
|
||||||
this.frm.save();
|
() => {
|
||||||
this.dialog.hide();
|
this.callback && this.callback(r.message);
|
||||||
|
},
|
||||||
|
() => this.frm.save(),
|
||||||
|
() => this.dialog.hide(),
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1329,6 +1329,15 @@ def create_serial_batch_no_ledgers(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
batch_no = None
|
||||||
|
|
||||||
|
if (
|
||||||
|
not entries[0].get("batch_no")
|
||||||
|
and entries[0].get("serial_no")
|
||||||
|
and frappe.get_cached_value("Item", child_row.item_code, "has_batch_no")
|
||||||
|
):
|
||||||
|
batch_no = get_batch(child_row.item_code)
|
||||||
|
|
||||||
for row in entries:
|
for row in entries:
|
||||||
row = frappe._dict(row)
|
row = frappe._dict(row)
|
||||||
doc.append(
|
doc.append(
|
||||||
@@ -1336,7 +1345,7 @@ def create_serial_batch_no_ledgers(
|
|||||||
{
|
{
|
||||||
"qty": (flt(row.qty) or 1.0) * (1 if type_of_transaction == "Inward" else -1),
|
"qty": (flt(row.qty) or 1.0) * (1 if type_of_transaction == "Inward" else -1),
|
||||||
"warehouse": warehouse,
|
"warehouse": warehouse,
|
||||||
"batch_no": row.batch_no,
|
"batch_no": row.batch_no or batch_no,
|
||||||
"serial_no": row.serial_no,
|
"serial_no": row.serial_no,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -1351,6 +1360,18 @@ def create_serial_batch_no_ledgers(
|
|||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
def get_batch(item_code):
|
||||||
|
from erpnext.stock.doctype.batch.batch import make_batch
|
||||||
|
|
||||||
|
return make_batch(
|
||||||
|
frappe._dict(
|
||||||
|
{
|
||||||
|
"item": item_code,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_type_of_transaction(parent_doc, child_row):
|
def get_type_of_transaction(parent_doc, child_row):
|
||||||
type_of_transaction = child_row.get("type_of_transaction")
|
type_of_transaction = child_row.get("type_of_transaction")
|
||||||
if parent_doc.get("doctype") == "Stock Entry":
|
if parent_doc.get("doctype") == "Stock Entry":
|
||||||
|
|||||||
Reference in New Issue
Block a user