mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-06 05:39:12 +00:00
Merge branch 'develop' into bank-trans-party-automatch
This commit is contained in:
@@ -1,260 +1,126 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "hash",
|
||||
"beta": 0,
|
||||
"creation": "2013-02-22 01:27:51",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2013-02-22 01:27:51",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"item_code",
|
||||
"serial_and_batch_bundle",
|
||||
"serial_no",
|
||||
"qty",
|
||||
"description",
|
||||
"prevdoc_detail_docname",
|
||||
"prevdoc_docname",
|
||||
"prevdoc_doctype"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Code",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "item_code",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Item",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Item Code",
|
||||
"oldfieldname": "item_code",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Item",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "serial_no",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Serial No",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "serial_no",
|
||||
"oldfieldtype": "Small Text",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "180px",
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"fieldname": "serial_no",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Serial No",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "serial_no",
|
||||
"oldfieldtype": "Small Text",
|
||||
"print_hide": 1,
|
||||
"print_width": "180px",
|
||||
"width": "180px"
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Installed Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "qty",
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Installed Qty",
|
||||
"oldfieldname": "qty",
|
||||
"oldfieldtype": "Currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "300px",
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Data",
|
||||
"print_width": "300px",
|
||||
"read_only": 1,
|
||||
"width": "300px"
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "prevdoc_detail_docname",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Against Document Detail No",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_detail_docname",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "150px",
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"fieldname": "prevdoc_detail_docname",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Against Document Detail No",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_detail_docname",
|
||||
"oldfieldtype": "Data",
|
||||
"print_hide": 1,
|
||||
"print_width": "150px",
|
||||
"read_only": 1,
|
||||
"width": "150px"
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "prevdoc_docname",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Against Document No",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_docname",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "150px",
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"fieldname": "prevdoc_docname",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Against Document No",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_docname",
|
||||
"oldfieldtype": "Data",
|
||||
"print_hide": 1,
|
||||
"print_width": "150px",
|
||||
"read_only": 1,
|
||||
"search_index": 1,
|
||||
"width": "150px"
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "prevdoc_doctype",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Document Type",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_doctype",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "150px",
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"fieldname": "prevdoc_doctype",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Document Type",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_doctype",
|
||||
"oldfieldtype": "Data",
|
||||
"print_hide": 1,
|
||||
"print_width": "150px",
|
||||
"read_only": 1,
|
||||
"search_index": 1,
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"fieldname": "serial_and_batch_bundle",
|
||||
"fieldtype": "Link",
|
||||
"label": "Serial and Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-02-20 13:24:18.142419",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Installation Note Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-03-12 13:47:08.257955",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Installation Note Item",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -415,10 +415,17 @@ class SalesOrder(SellingController):
|
||||
def update_picking_status(self):
|
||||
total_picked_qty = 0.0
|
||||
total_qty = 0.0
|
||||
per_picked = 0.0
|
||||
|
||||
for so_item in self.items:
|
||||
total_picked_qty += flt(so_item.picked_qty)
|
||||
total_qty += flt(so_item.stock_qty)
|
||||
per_picked = total_picked_qty / total_qty * 100
|
||||
if cint(
|
||||
frappe.get_cached_value("Item", so_item.item_code, "is_stock_item")
|
||||
) or self.has_product_bundle(so_item.item_code):
|
||||
total_picked_qty += flt(so_item.picked_qty)
|
||||
total_qty += flt(so_item.stock_qty)
|
||||
|
||||
if total_picked_qty and total_qty:
|
||||
per_picked = total_picked_qty / total_qty * 100
|
||||
|
||||
self.db_set("per_picked", flt(per_picked), update_modified=False)
|
||||
|
||||
|
||||
@@ -1254,112 +1254,6 @@ class TestSalesOrder(FrappeTestCase):
|
||||
)
|
||||
self.assertEqual(wo_qty[0][0], so_item_name.get(item))
|
||||
|
||||
def test_serial_no_based_delivery(self):
|
||||
frappe.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1)
|
||||
item = make_item(
|
||||
"_Reserved_Serialized_Item",
|
||||
{
|
||||
"is_stock_item": 1,
|
||||
"maintain_stock": 1,
|
||||
"has_serial_no": 1,
|
||||
"serial_no_series": "SI.####",
|
||||
"valuation_rate": 500,
|
||||
"item_defaults": [{"default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company"}],
|
||||
},
|
||||
)
|
||||
frappe.db.sql("""delete from `tabSerial No` where item_code=%s""", (item.item_code))
|
||||
make_item(
|
||||
"_Test Item A",
|
||||
{
|
||||
"maintain_stock": 1,
|
||||
"valuation_rate": 100,
|
||||
"item_defaults": [{"default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company"}],
|
||||
},
|
||||
)
|
||||
make_item(
|
||||
"_Test Item B",
|
||||
{
|
||||
"maintain_stock": 1,
|
||||
"valuation_rate": 200,
|
||||
"item_defaults": [{"default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company"}],
|
||||
},
|
||||
)
|
||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
||||
|
||||
make_bom(item=item.item_code, rate=1000, raw_materials=["_Test Item A", "_Test Item B"])
|
||||
|
||||
so = make_sales_order(
|
||||
**{
|
||||
"item_list": [
|
||||
{
|
||||
"item_code": item.item_code,
|
||||
"ensure_delivery_based_on_produced_serial_no": 1,
|
||||
"qty": 1,
|
||||
"rate": 1000,
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
so.submit()
|
||||
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
|
||||
|
||||
work_order = make_wo_order_test_record(item=item.item_code, qty=1, do_not_save=True)
|
||||
work_order.fg_warehouse = "_Test Warehouse - _TC"
|
||||
work_order.sales_order = so.name
|
||||
work_order.submit()
|
||||
make_stock_entry(item_code=item.item_code, target="_Test Warehouse - _TC", qty=1)
|
||||
item_serial_no = frappe.get_doc("Serial No", {"item_code": item.item_code})
|
||||
from erpnext.manufacturing.doctype.work_order.work_order import (
|
||||
make_stock_entry as make_production_stock_entry,
|
||||
)
|
||||
|
||||
se = frappe.get_doc(make_production_stock_entry(work_order.name, "Manufacture", 1))
|
||||
se.submit()
|
||||
reserved_serial_no = se.get("items")[2].serial_no
|
||||
serial_no_so = frappe.get_value("Serial No", reserved_serial_no, "sales_order")
|
||||
self.assertEqual(serial_no_so, so.name)
|
||||
dn = make_delivery_note(so.name)
|
||||
dn.save()
|
||||
self.assertEqual(reserved_serial_no, dn.get("items")[0].serial_no)
|
||||
item_line = dn.get("items")[0]
|
||||
item_line.serial_no = item_serial_no.name
|
||||
item_line = dn.get("items")[0]
|
||||
item_line.serial_no = reserved_serial_no
|
||||
dn.submit()
|
||||
dn.load_from_db()
|
||||
dn.cancel()
|
||||
si = make_sales_invoice(so.name)
|
||||
si.update_stock = 1
|
||||
si.save()
|
||||
self.assertEqual(si.get("items")[0].serial_no, reserved_serial_no)
|
||||
item_line = si.get("items")[0]
|
||||
item_line.serial_no = item_serial_no.name
|
||||
self.assertRaises(frappe.ValidationError, dn.submit)
|
||||
item_line = si.get("items")[0]
|
||||
item_line.serial_no = reserved_serial_no
|
||||
self.assertTrue(si.submit)
|
||||
si.submit()
|
||||
si.load_from_db()
|
||||
si.cancel()
|
||||
si = make_sales_invoice(so.name)
|
||||
si.update_stock = 0
|
||||
si.submit()
|
||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
|
||||
make_delivery_note as make_delivery_note_from_invoice,
|
||||
)
|
||||
|
||||
dn = make_delivery_note_from_invoice(si.name)
|
||||
dn.save()
|
||||
dn.submit()
|
||||
self.assertEqual(dn.get("items")[0].serial_no, reserved_serial_no)
|
||||
dn.load_from_db()
|
||||
dn.cancel()
|
||||
si.load_from_db()
|
||||
si.cancel()
|
||||
se.load_from_db()
|
||||
se.cancel()
|
||||
self.assertFalse(frappe.db.exists("Serial No", {"sales_order": so.name}))
|
||||
|
||||
def test_advance_payment_entry_unlink_against_sales_order(self):
|
||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||
|
||||
@@ -1878,7 +1772,14 @@ class TestSalesOrder(FrappeTestCase):
|
||||
self.assertEqual(pe.references[1].reference_name, so.name)
|
||||
self.assertEqual(pe.references[1].allocated_amount, 300)
|
||||
|
||||
@change_settings("Stock Settings", {"enable_stock_reservation": 1})
|
||||
@change_settings(
|
||||
"Stock Settings",
|
||||
{
|
||||
"enable_stock_reservation": 1,
|
||||
"auto_create_serial_and_batch_bundle_for_outward": 1,
|
||||
"pick_serial_and_batch_based_on": "FIFO",
|
||||
},
|
||||
)
|
||||
def test_stock_reservation_against_sales_order(self) -> None:
|
||||
from random import randint, uniform
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
<div class="item-image"></div>
|
||||
</div>
|
||||
<div class="discount-section"></div>
|
||||
<div class="form-container"></div>`
|
||||
<div class="form-container"></div>
|
||||
<div class="serial-batch-container"></div>`
|
||||
)
|
||||
|
||||
this.$item_name = this.$component.find('.item-name');
|
||||
@@ -53,6 +54,7 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
this.$item_image = this.$component.find('.item-image');
|
||||
this.$form_container = this.$component.find('.form-container');
|
||||
this.$dicount_section = this.$component.find('.discount-section');
|
||||
this.$serial_batch_container = this.$component.find('.serial-batch-container');
|
||||
}
|
||||
|
||||
compare_with_current_item(item) {
|
||||
@@ -101,12 +103,9 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
|
||||
const serialized = item_row.has_serial_no;
|
||||
const batched = item_row.has_batch_no;
|
||||
const no_serial_selected = !item_row.serial_no;
|
||||
const no_batch_selected = !item_row.batch_no;
|
||||
|
||||
if ((serialized && no_serial_selected) || (batched && no_batch_selected) ||
|
||||
(serialized && batched && (no_batch_selected || no_serial_selected))) {
|
||||
const no_bundle_selected = !item_row.serial_and_batch_bundle;
|
||||
|
||||
if ((serialized && no_bundle_selected) || (batched && no_bundle_selected)) {
|
||||
frappe.show_alert({
|
||||
message: __("Item is removed since no serial / batch no selected."),
|
||||
indicator: 'orange'
|
||||
@@ -200,13 +199,8 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
}
|
||||
|
||||
make_auto_serial_selection_btn(item) {
|
||||
if (item.has_serial_no) {
|
||||
if (!item.has_batch_no) {
|
||||
this.$form_container.append(
|
||||
`<div class="grid-filler no-select"></div>`
|
||||
);
|
||||
}
|
||||
const label = __('Auto Fetch Serial Numbers');
|
||||
if (item.has_serial_no || item.has_batch_no) {
|
||||
const label = item.has_serial_no ? __('Select Serial No') : __('Select Batch No');
|
||||
this.$form_container.append(
|
||||
`<div class="btn btn-sm btn-secondary auto-fetch-btn">${label}</div>`
|
||||
);
|
||||
@@ -382,40 +376,20 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
|
||||
bind_auto_serial_fetch_event() {
|
||||
this.$form_container.on('click', '.auto-fetch-btn', () => {
|
||||
this.batch_no_control && this.batch_no_control.set_value('');
|
||||
let qty = this.qty_control.get_value();
|
||||
let conversion_factor = this.conversion_factor_control.get_value();
|
||||
let expiry_date = this.item_row.has_batch_no ? this.events.get_frm().doc.posting_date : "";
|
||||
frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", () => {
|
||||
let frm = this.events.get_frm();
|
||||
let item_row = this.item_row;
|
||||
item_row.outward = 1;
|
||||
item_row.type_of_transaction = "Outward";
|
||||
|
||||
let numbers = frappe.call({
|
||||
method: "erpnext.stock.doctype.serial_no.serial_no.auto_fetch_serial_number",
|
||||
args: {
|
||||
qty: qty * conversion_factor,
|
||||
item_code: this.current_item.item_code,
|
||||
warehouse: this.warehouse_control.get_value() || '',
|
||||
batch_nos: this.current_item.batch_no || '',
|
||||
posting_date: expiry_date,
|
||||
for_doctype: 'POS Invoice'
|
||||
}
|
||||
});
|
||||
|
||||
numbers.then((data) => {
|
||||
let auto_fetched_serial_numbers = data.message;
|
||||
let records_length = auto_fetched_serial_numbers.length;
|
||||
if (!records_length) {
|
||||
const warehouse = this.warehouse_control.get_value().bold();
|
||||
const item_code = this.current_item.item_code.bold();
|
||||
frappe.msgprint(
|
||||
__('Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.', [item_code, warehouse])
|
||||
);
|
||||
} else if (records_length < qty) {
|
||||
frappe.msgprint(
|
||||
__('Fetched only {0} available serial numbers.', [records_length])
|
||||
);
|
||||
this.qty_control.set_value(records_length);
|
||||
}
|
||||
numbers = auto_fetched_serial_numbers.join(`\n`);
|
||||
this.serial_no_control.set_value(numbers);
|
||||
new erpnext.SerialBatchPackageSelector(frm, item_row, (r) => {
|
||||
if (r) {
|
||||
frappe.model.set_value(item_row.doctype, item_row.name, {
|
||||
"serial_and_batch_bundle": r.name,
|
||||
"qty": Math.abs(r.total_qty)
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@@ -196,48 +196,6 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
|
||||
refresh_field("incentives",row.name,row.parentfield);
|
||||
}
|
||||
|
||||
warehouse(doc, cdt, cdn) {
|
||||
var me = this;
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
|
||||
// check if serial nos entered are as much as qty in row
|
||||
if (item.serial_no) {
|
||||
let serial_nos = item.serial_no.split(`\n`).filter(sn => sn.trim()); // filter out whitespaces
|
||||
if (item.qty === serial_nos.length) return;
|
||||
}
|
||||
|
||||
if (item.serial_no && !item.batch_no) {
|
||||
item.serial_no = null;
|
||||
}
|
||||
|
||||
var has_batch_no;
|
||||
frappe.db.get_value('Item', {'item_code': item.item_code}, 'has_batch_no', (r) => {
|
||||
has_batch_no = r && r.has_batch_no;
|
||||
if(item.item_code && item.warehouse) {
|
||||
return this.frm.call({
|
||||
method: "erpnext.stock.get_item_details.get_bin_details_and_serial_nos",
|
||||
child: item,
|
||||
args: {
|
||||
item_code: item.item_code,
|
||||
warehouse: item.warehouse,
|
||||
has_batch_no: has_batch_no || 0,
|
||||
stock_qty: item.stock_qty,
|
||||
serial_no: item.serial_no || "",
|
||||
},
|
||||
callback:function(r){
|
||||
if (in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
|
||||
if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return;
|
||||
if (has_batch_no) {
|
||||
me.set_batch_number(cdt, cdn);
|
||||
me.batch_no(doc, cdt, cdn);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
toggle_editable_price_list_rate() {
|
||||
var df = frappe.meta.get_docfield(this.frm.doc.doctype + " Item", "price_list_rate", this.frm.doc.name);
|
||||
var editable_price_list_rate = cint(frappe.defaults.get_default("editable_price_list_rate"));
|
||||
@@ -298,36 +256,6 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
|
||||
}
|
||||
}
|
||||
|
||||
batch_no(doc, cdt, cdn) {
|
||||
super.batch_no(doc, cdt, cdn);
|
||||
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
|
||||
if (item.serial_no) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.serial_no = null;
|
||||
var has_serial_no;
|
||||
frappe.db.get_value('Item', {'item_code': item.item_code}, 'has_serial_no', (r) => {
|
||||
has_serial_no = r && r.has_serial_no;
|
||||
if(item.warehouse && item.item_code && item.batch_no) {
|
||||
return this.frm.call({
|
||||
method: "erpnext.stock.get_item_details.get_batch_qty_and_serial_no",
|
||||
child: item,
|
||||
args: {
|
||||
"batch_no": item.batch_no,
|
||||
"stock_qty": item.stock_qty || item.qty, //if stock_qty field is not available fetch qty (in case of Packed Items table)
|
||||
"warehouse": item.warehouse,
|
||||
"item_code": item.item_code,
|
||||
"has_serial_no": has_serial_no
|
||||
},
|
||||
"fieldname": "actual_batch_qty"
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
set_dynamic_labels() {
|
||||
super.set_dynamic_labels();
|
||||
this.set_product_bundle_help(this.frm.doc);
|
||||
@@ -372,52 +300,46 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
|
||||
|
||||
conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate) {
|
||||
super.conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate);
|
||||
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn) &&
|
||||
in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
|
||||
if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return;
|
||||
this.set_batch_number(cdt, cdn);
|
||||
}
|
||||
}
|
||||
|
||||
qty(doc, cdt, cdn) {
|
||||
super.qty(doc, cdt, cdn);
|
||||
|
||||
if(in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
|
||||
if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return;
|
||||
this.set_batch_number(cdt, cdn);
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine appropriate batch number and set it in the form.
|
||||
* @param {string} cdt - Document Doctype
|
||||
* @param {string} cdn - Document name
|
||||
*/
|
||||
set_batch_number(cdt, cdn) {
|
||||
const doc = frappe.get_doc(cdt, cdn);
|
||||
if (doc && doc.has_batch_no && doc.warehouse) {
|
||||
this._set_batch_number(doc);
|
||||
}
|
||||
}
|
||||
pick_serial_and_batch(doc, cdt, cdn) {
|
||||
let item = locals[cdt][cdn];
|
||||
let me = this;
|
||||
let path = "assets/erpnext/js/utils/serial_no_batch_selector.js";
|
||||
|
||||
_set_batch_number(doc) {
|
||||
if (doc.batch_no) {
|
||||
return
|
||||
}
|
||||
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;
|
||||
item.type_of_transaction = item.qty > 0 ? "Outward":"Inward";
|
||||
item.outward = item.qty > 0 ? 1 : 0;
|
||||
|
||||
let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)};
|
||||
if (doc.has_serial_no && doc.serial_no) {
|
||||
args['serial_no'] = doc.serial_no
|
||||
}
|
||||
item.title = item.has_serial_no ?
|
||||
__("Select Serial No") : __("Select Batch No");
|
||||
|
||||
return frappe.call({
|
||||
method: 'erpnext.stock.doctype.batch.batch.get_batch_no',
|
||||
args: args,
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
frappe.model.set_value(doc.doctype, doc.name, 'batch_no', r.message);
|
||||
if (item.has_serial_no && item.has_batch_no) {
|
||||
item.title = __("Select Serial and Batch");
|
||||
}
|
||||
|
||||
frappe.require(path, function() {
|
||||
new erpnext.SerialBatchPackageSelector(
|
||||
me.frm, item, (r) => {
|
||||
if (r) {
|
||||
frappe.model.set_value(item.doctype, item.name, {
|
||||
"serial_and_batch_bundle": r.name,
|
||||
"qty": Math.abs(r.total_qty)
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
update_auto_repeat_reference(doc) {
|
||||
|
||||
Reference in New Issue
Block a user