Merge pull request #39496 from frappe/mergify/bp/version-15-hotfix/pr-39478
fix: UX improvements for Serial and Batch Bundle (backport #39478)
This commit is contained in:
commit
1331fb75a3
@ -105,11 +105,27 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
||||
this.frm.has_items = false;
|
||||
}
|
||||
|
||||
if (serial_no && this.is_duplicate_serial_no(row, item_code, serial_no)) {
|
||||
if (serial_no) {
|
||||
this.is_duplicate_serial_no(row, item_code, serial_no)
|
||||
.then((is_duplicate) => {
|
||||
if (!is_duplicate) {
|
||||
this.run_serially_tasks(row, data, resolve);
|
||||
} else {
|
||||
this.clean_up();
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.run_serially_tasks(row, data, resolve);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
run_serially_tasks(row, data, resolve) {
|
||||
const {item_code, barcode, batch_no, serial_no, uom} = data;
|
||||
|
||||
frappe.run_serially([
|
||||
() => this.set_serial_and_batch(row, item_code, serial_no, batch_no),
|
||||
@ -119,16 +135,15 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
||||
}),
|
||||
() => this.set_barcode_uom(row, uom),
|
||||
() => this.clean_up(),
|
||||
() => resolve(row),
|
||||
() => {
|
||||
if (row.serial_and_batch_bundle && !this.frm.is_new()) {
|
||||
this.frm.save();
|
||||
}
|
||||
|
||||
frappe.flags.trigger_from_barcode_scanner = false;
|
||||
}
|
||||
},
|
||||
() => resolve(row),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
set_item(row, item_code, barcode, batch_no, serial_no) {
|
||||
@ -475,26 +490,32 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
||||
}
|
||||
}
|
||||
|
||||
is_duplicate_serial_no(row, item_code, serial_no) {
|
||||
async is_duplicate_serial_no(row, item_code, serial_no) {
|
||||
let is_duplicate = false;
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
if (this.frm.is_new() || !row.serial_and_batch_bundle) {
|
||||
let is_duplicate = this.check_duplicate_serial_no_in_localstorage(item_code, serial_no);
|
||||
is_duplicate = this.check_duplicate_serial_no_in_localstorage(item_code, serial_no);
|
||||
if (is_duplicate) {
|
||||
this.show_alert(__("Serial No {0} is already added", [serial_no]), "orange");
|
||||
}
|
||||
|
||||
return is_duplicate;
|
||||
resolve(is_duplicate);
|
||||
} else if (row.serial_and_batch_bundle) {
|
||||
this.check_duplicate_serial_no_in_db(row, serial_no, (r) => {
|
||||
if (r.message) {
|
||||
this.show_alert(__("Serial No {0} is already added", [serial_no]), "orange");
|
||||
}
|
||||
|
||||
return r.message;
|
||||
is_duplicate = r.message;
|
||||
resolve(is_duplicate);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
return await promise;
|
||||
}
|
||||
|
||||
async check_duplicate_serial_no_in_db(row, serial_no, response) {
|
||||
check_duplicate_serial_no_in_db(row, serial_no, response) {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.is_duplicate_serial_no",
|
||||
args: {
|
||||
@ -504,7 +525,7 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner {
|
||||
callback(r) {
|
||||
response(r);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
check_duplicate_serial_no_in_localstorage(item_code, serial_no) {
|
||||
|
@ -135,7 +135,7 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
filters: this.get_serial_no_filters()
|
||||
};
|
||||
},
|
||||
onchange: () => this.update_serial_batch_no()
|
||||
onchange: () => this.scan_barcode_data()
|
||||
});
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
options: 'Barcode',
|
||||
fieldname: 'scan_batch_no',
|
||||
label: __('Scan Batch No'),
|
||||
onchange: () => this.update_serial_batch_no()
|
||||
onchange: () => this.scan_barcode_data()
|
||||
});
|
||||
}
|
||||
|
||||
@ -179,11 +179,54 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
label = __('Serial Nos / Batch Nos');
|
||||
}
|
||||
|
||||
return [
|
||||
let fields = [
|
||||
{
|
||||
fieldtype: 'Section Break',
|
||||
label: __('{0} {1} via CSV File', [primary_label, label])
|
||||
}
|
||||
]
|
||||
|
||||
if (this.item?.has_serial_no) {
|
||||
fields = [...fields,
|
||||
{
|
||||
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: '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,
|
||||
{
|
||||
fieldtype: 'Button',
|
||||
fieldname: 'download_csv',
|
||||
@ -199,7 +242,32 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
label: __('Attach CSV File'),
|
||||
onchange: () => this.upload_csv_file()
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
create_serial_nos() {
|
||||
let {upload_serial_nos} = this.dialog.get_values();
|
||||
|
||||
if (!upload_serial_nos) {
|
||||
frappe.throw(__('Please enter Serial Nos'));
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.create_serial_nos',
|
||||
args: {
|
||||
item_code: this.item.item_code,
|
||||
serial_nos: upload_serial_nos
|
||||
},
|
||||
callback: (r) => {
|
||||
if (r.message) {
|
||||
this.dialog.fields_dict.entries.df.data = [];
|
||||
this.set_data(r.message);
|
||||
this.update_bundle_entries();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
download_csv_file() {
|
||||
@ -374,6 +442,26 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
scan_barcode_data() {
|
||||
const { scan_serial_no, scan_batch_no } = this.dialog.get_values();
|
||||
|
||||
if (scan_serial_no || scan_batch_no) {
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.is_serial_batch_no_exists',
|
||||
args: {
|
||||
item_code: this.item.item_code,
|
||||
type_of_transaction: this.item.type_of_transaction,
|
||||
serial_no: scan_serial_no,
|
||||
batch_no: scan_batch_no,
|
||||
},
|
||||
callback: (r) => {
|
||||
this.update_serial_batch_no();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
update_serial_batch_no() {
|
||||
const { scan_serial_no, scan_batch_no } = this.dialog.get_values();
|
||||
|
||||
|
@ -74,7 +74,7 @@ frappe.ui.form.on('Serial and Batch Bundle', {
|
||||
|
||||
let fields = [
|
||||
{
|
||||
"label": __("Using CSV File"),
|
||||
"label": __("Import Using CSV file"),
|
||||
"fieldname": "using_csv_file",
|
||||
"default": 1,
|
||||
"fieldtype": "Check",
|
||||
|
@ -999,9 +999,25 @@ def get_serial_batch_from_data(item_code, kwargs):
|
||||
|
||||
make_serial_nos(item_code, serial_nos)
|
||||
|
||||
if kwargs.get("_has_serial_nos"):
|
||||
return serial_nos
|
||||
|
||||
return serial_nos, batch_nos
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_serial_nos(item_code, serial_nos):
|
||||
serial_nos = get_serial_batch_from_data(
|
||||
item_code,
|
||||
{
|
||||
"serial_nos": serial_nos,
|
||||
"_has_serial_nos": True,
|
||||
},
|
||||
)
|
||||
|
||||
return serial_nos
|
||||
|
||||
|
||||
def make_serial_nos(item_code, serial_nos):
|
||||
item = frappe.get_cached_value("Item", item_code, ["description", "item_code"], as_dict=1)
|
||||
|
||||
@ -2079,6 +2095,35 @@ def get_batch_no_from_serial_no(serial_no):
|
||||
return frappe.get_cached_value("Serial No", serial_no, "batch_no")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def is_serial_batch_no_exists(item_code, type_of_transaction, serial_no=None, batch_no=None):
|
||||
if serial_no and not frappe.db.exists("Serial No", serial_no):
|
||||
if type_of_transaction != "Inward":
|
||||
frappe.throw(_("Serial No {0} does not exists").format(serial_no))
|
||||
|
||||
make_serial_no(serial_no, item_code)
|
||||
|
||||
if batch_no and frappe.db.exists("Batch", batch_no):
|
||||
if type_of_transaction != "Inward":
|
||||
frappe.throw(_("Batch No {0} does not exists").format(batch_no))
|
||||
|
||||
make_batch_no(batch_no, item_code)
|
||||
|
||||
|
||||
def make_serial_no(serial_no, item_code):
|
||||
serial_no_doc = frappe.new_doc("Serial No")
|
||||
serial_no_doc.serial_no = serial_no
|
||||
serial_no_doc.item_code = item_code
|
||||
serial_no_doc.save(ignore_permissions=True)
|
||||
|
||||
|
||||
def make_batch_no(batch_no, item_code):
|
||||
batch_doc = frappe.new_doc("Batch")
|
||||
batch_doc.batch_id = batch_no
|
||||
batch_doc.item = item_code
|
||||
batch_doc.save(ignore_permissions=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def is_duplicate_serial_no(bundle_id, serial_no):
|
||||
return frappe.db.exists("Serial and Batch Entry", {"parent": bundle_id, "serial_no": serial_no})
|
||||
|
Loading…
x
Reference in New Issue
Block a user