Skip to content

Commit

Permalink
fix: use serial batch fields for subcontracting receipt (backport #40311
Browse files Browse the repository at this point in the history
) (#40315)

fix: use serial batch fields for subcontracting receipt (#40311)

(cherry picked from commit cef6291)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
  • Loading branch information
mergify[bot] and rohitwaghchaure authored Mar 6, 2024
1 parent 7001e0a commit 4b15c00
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 114 deletions.
12 changes: 12 additions & 0 deletions erpnext/controllers/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,9 +434,21 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):

filtered_batches = get_filterd_batches(batches)

if filters.get("is_inward"):
filtered_batches.extend(get_empty_batches(filters))

return filtered_batches


def get_empty_batches(filters):
return frappe.get_all(
"Batch",
fields=["name", "batch_qty"],
filters={"item": filters.get("item_code"), "batch_qty": 0.0},
as_list=1,
)


def get_filterd_batches(data):
batches = OrderedDict()

Expand Down
82 changes: 45 additions & 37 deletions erpnext/controllers/stock_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,43 +190,23 @@ def make_bundle_using_old_serial_batch_fields(self, table_name=None):
if row.use_serial_batch_fields and (
not row.serial_and_batch_bundle and not row.get("rejected_serial_and_batch_bundle")
):
if self.doctype == "Stock Reconciliation":
qty = row.qty
type_of_transaction = "Inward"
warehouse = row.warehouse
elif table_name == "packed_items":
qty = row.qty
warehouse = row.warehouse
type_of_transaction = "Outward"
if self.is_return:
type_of_transaction = "Inward"
else:
qty = row.stock_qty if self.doctype != "Stock Entry" else row.transfer_qty
type_of_transaction = get_type_of_transaction(self, row)
warehouse = (
row.warehouse if self.doctype != "Stock Entry" else row.s_warehouse or row.t_warehouse
)

sn_doc = SerialBatchCreation(
{
"item_code": row.item_code,
"warehouse": warehouse,
"posting_date": self.posting_date,
"posting_time": self.posting_time,
"voucher_type": self.doctype,
"voucher_no": self.name,
"voucher_detail_no": row.name,
"qty": qty,
"type_of_transaction": type_of_transaction,
"company": self.company,
"is_rejected": 1 if row.get("rejected_warehouse") else 0,
"serial_nos": get_serial_nos(row.serial_no) if row.serial_no else None,
"batches": frappe._dict({row.batch_no: qty}) if row.batch_no else None,
"batch_no": row.batch_no,
"use_serial_batch_fields": row.use_serial_batch_fields,
"do_not_submit": True,
}
).make_serial_and_batch_bundle()
bundle_details = {
"item_code": row.item_code,
"posting_date": self.posting_date,
"posting_time": self.posting_time,
"voucher_type": self.doctype,
"voucher_no": self.name,
"voucher_detail_no": row.name,
"company": self.company,
"is_rejected": 1 if row.get("rejected_warehouse") else 0,
"serial_nos": get_serial_nos(row.serial_no) if row.serial_no else None,
"batch_no": row.batch_no,
"use_serial_batch_fields": row.use_serial_batch_fields,
"do_not_submit": True,
}

self.update_bundle_details(bundle_details, table_name, row)
sn_doc = SerialBatchCreation(bundle_details).make_serial_and_batch_bundle()

if sn_doc.is_rejected:
row.rejected_serial_and_batch_bundle = sn_doc.name
Expand All @@ -243,6 +223,34 @@ def make_bundle_using_old_serial_batch_fields(self, table_name=None):
}
)

def update_bundle_details(self, bundle_details, table_name, row):
# Since qty field is different for different doctypes
qty = row.get("qty")
warehouse = row.get("warehouse")

if table_name == "packed_items":
type_of_transaction = "Inward"
if not self.is_return:
type_of_transaction = "Outward"
else:
type_of_transaction = get_type_of_transaction(self, row)

if hasattr(row, "stock_qty"):
qty = row.stock_qty

if self.doctype == "Stock Entry":
qty = row.transfer_qty
warehouse = row.s_warehouse or row.t_warehouse

bundle_details.update(
{
"qty": qty,
"type_of_transaction": type_of_transaction,
"warehouse": warehouse,
"batches": frappe._dict({row.batch_no: qty}) if row.batch_no else None,
}
)

def validate_serial_nos_and_batches_with_bundle(self, row):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos

Expand Down
9 changes: 8 additions & 1 deletion erpnext/public/js/utils/serial_no_batch_selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,11 +371,18 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
label: __('Batch No'),
in_list_view: 1,
get_query: () => {
let is_inward = false;
if ((["Purchase Receipt", "Purchase Invoice"].includes(this.frm.doc.doctype) && !this.frm.doc.is_return)
|| (this.frm.doc.doctype === 'Stock Entry' && this.frm.doc.purpose === 'Material Receipt')) {
is_inward = true;
}

return {
query : "erpnext.controllers.queries.get_batch_no",
filters: {
'item_code': this.item.item_code,
'warehouse': this.item.s_warehouse || this.item.t_warehouse,
'warehouse': this.item.s_warehouse || this.item.t_warehouse || this.item.warehouse,
'is_inward': is_inward
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,13 @@ def get_type_of_transaction(parent_doc, child_row):
if parent_doc.get("is_return"):
type_of_transaction = "Inward" if type_of_transaction == "Outward" else "Outward"

if parent_doc.get("doctype") == "Subcontracting Receipt":
type_of_transaction = "Outward"
if child_row.get("doctype") == "Subcontracting Receipt Item":
type_of_transaction = "Inward"
elif parent_doc.get("doctype") == "Stock Reconciliation":
type_of_transaction = "Inward"

return type_of_transaction


Expand Down
47 changes: 1 addition & 46 deletions erpnext/stock/doctype/stock_entry/stock_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,7 @@
from frappe import _
from frappe.model.mapper import get_mapped_doc
from frappe.query_builder.functions import Sum
from frappe.utils import (
cint,
comma_or,
cstr,
flt,
format_time,
formatdate,
getdate,
month_diff,
nowdate,
)
from frappe.utils import cint, comma_or, cstr, flt, format_time, formatdate, getdate, nowdate

import erpnext
from erpnext.accounts.general_ledger import process_gl_map
Expand Down Expand Up @@ -237,41 +227,6 @@ def validate(self):
self.reset_default_field_value("from_warehouse", "items", "s_warehouse")
self.reset_default_field_value("to_warehouse", "items", "t_warehouse")

def submit(self):
if self.is_enqueue_action():
frappe.msgprint(
_(
"The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Entry and revert to the Draft stage"
)
)
self.queue_action("submit", timeout=2000)
else:
self._submit()

def cancel(self):
if self.is_enqueue_action():
frappe.msgprint(
_(
"The task has been enqueued as a background job. In case there is any issue on processing in background, the system will add a comment about the error on this Stock Entry and revert to the Submitted stage"
)
)
self.queue_action("cancel", timeout=2000)
else:
self._cancel()

def is_enqueue_action(self, force=False) -> bool:
if force:
return True

if frappe.flags.in_test:
return False

# If line items are more than 100 or record is older than 6 months
if len(self.items) > 50 or month_diff(nowdate(), self.posting_date) > 6:
return True

return False

def on_submit(self):
self.validate_closed_subcontracting_order()
self.make_bundle_using_old_serial_batch_fields()
Expand Down
30 changes: 0 additions & 30 deletions erpnext/stock/doctype/stock_entry/test_stock_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1633,36 +1633,6 @@ def test_negative_stock_reco(self):

self.assertRaises(frappe.ValidationError, sr_doc.submit)

def test_enqueue_action(self):
frappe.flags.in_test = False
item_code = "Test Enqueue Item - 001"
create_item(item_code=item_code, is_stock_item=1, valuation_rate=10)

doc = make_stock_entry(
item_code=item_code,
posting_date=add_to_date(today(), months=-7),
posting_time="00:00:00",
purpose="Material Receipt",
qty=10,
to_warehouse="_Test Warehouse - _TC",
do_not_submit=True,
)

self.assertTrue(doc.is_enqueue_action())

doc = make_stock_entry(
item_code=item_code,
posting_date=today(),
posting_time="00:00:00",
purpose="Material Receipt",
qty=10,
to_warehouse="_Test Warehouse - _TC",
do_not_submit=True,
)

self.assertFalse(doc.is_enqueue_action())
frappe.flags.in_test = True

def test_negative_batch(self):
item_code = "Test Negative Batch Item - 001"
make_item(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,77 @@ def test_auto_create_purchase_receipt(self):

self.assertTrue(frappe.db.get_value("Purchase Receipt", {"subcontracting_receipt": scr.name}))

def test_use_serial_batch_fields_for_subcontracting_receipt(self):
fg_item = make_item(
"Test Subcontracted Item With Batch No",
properties={
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "BATCH-BNGS-.####",
"is_sub_contracted_item": 1,
},
).name

make_item(
"Test Subcontracted Item With Batch No Service Item 1",
properties={"is_stock_item": 0},
)

make_bom(
item=fg_item,
raw_materials=[
make_item(
"Test Subcontracted Item With Batch No RM Item 1",
properties={
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "BATCH-RM-BNGS-.####",
},
).name
],
)

service_items = [
{
"warehouse": "_Test Warehouse - _TC",
"item_code": "Test Subcontracted Item With Batch No Service Item 1",
"qty": 1,
"rate": 100,
"fg_item": fg_item,
"fg_item_qty": 1,
},
]
sco = get_subcontracting_order(service_items=service_items)
rm_items = get_rm_items(sco.supplied_items)
itemwise_details = make_stock_in_entry(rm_items=rm_items)
make_stock_transfer_entry(
sco_no=sco.name,
rm_items=rm_items,
itemwise_details=copy.deepcopy(itemwise_details),
)

batch_no = "BATCH-BNGS-0001"
if not frappe.db.exists("Batch", batch_no):
frappe.get_doc(
{
"doctype": "Batch",
"batch_id": batch_no,
"item": fg_item,
}
).insert()

scr = make_subcontracting_receipt(sco.name)
self.assertFalse(scr.items[0].serial_and_batch_bundle)
scr.items[0].use_serial_batch_fields = 1
scr.items[0].batch_no = batch_no

scr.save()
scr.submit()
scr.reload()
self.assertTrue(scr.items[0].serial_and_batch_bundle)


def make_return_subcontracting_receipt(**args):
args = frappe._dict(args)
Expand Down

0 comments on commit 4b15c00

Please sign in to comment.