mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-01 11:19:09 +00:00
perf: DN submission with SABB
This commit is contained in:
@@ -2074,6 +2074,11 @@ def make_bundle_for_material_transfer(**kwargs):
|
|||||||
row.is_outward = 1
|
row.is_outward = 1
|
||||||
|
|
||||||
row.warehouse = kwargs.warehouse
|
row.warehouse = kwargs.warehouse
|
||||||
|
row.posting_datetime = bundle_doc.posting_datetime
|
||||||
|
row.voucher_type = bundle_doc.voucher_type
|
||||||
|
row.voucher_no = bundle_doc.voucher_no
|
||||||
|
row.voucher_detail_no = bundle_doc.voucher_detail_no
|
||||||
|
row.type_of_transaction = bundle_doc.type_of_transaction
|
||||||
|
|
||||||
bundle_doc.set_incoming_rate()
|
bundle_doc.set_incoming_rate()
|
||||||
bundle_doc.calculate_qty_and_amount()
|
bundle_doc.calculate_qty_and_amount()
|
||||||
|
|||||||
@@ -1300,11 +1300,25 @@ class SerialandBatchBundle(Document):
|
|||||||
def before_submit(self):
|
def before_submit(self):
|
||||||
self.validate_serial_and_batch_data()
|
self.validate_serial_and_batch_data()
|
||||||
self.validate_serial_and_batch_no_for_returned()
|
self.validate_serial_and_batch_no_for_returned()
|
||||||
|
self.set_child_details()
|
||||||
self.set_source_document_no()
|
self.set_source_document_no()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.validate_serial_nos_inventory()
|
self.validate_serial_nos_inventory()
|
||||||
|
|
||||||
|
def set_child_details(self):
|
||||||
|
for row in self.entries:
|
||||||
|
for field in [
|
||||||
|
"warehouse",
|
||||||
|
"posting_datetime",
|
||||||
|
"voucher_type",
|
||||||
|
"voucher_no",
|
||||||
|
"voucher_detail_no",
|
||||||
|
"type_of_transaction",
|
||||||
|
]:
|
||||||
|
if not row.get(field) or row.get(field) != self.get(field):
|
||||||
|
row.set(field, self.get(field))
|
||||||
|
|
||||||
def set_source_document_no(self):
|
def set_source_document_no(self):
|
||||||
if self.flags.ignore_validate_serial_batch:
|
if self.flags.ignore_validate_serial_batch:
|
||||||
return
|
return
|
||||||
@@ -3033,7 +3047,3 @@ def get_stock_reco_details(voucher_detail_no):
|
|||||||
],
|
],
|
||||||
as_dict=True,
|
as_dict=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def on_doctype_update():
|
|
||||||
frappe.db.add_index("Serial and Batch Bundle", ["item_code", "warehouse", "posting_datetime", "creation"])
|
|
||||||
|
|||||||
@@ -19,7 +19,13 @@
|
|||||||
"is_outward",
|
"is_outward",
|
||||||
"stock_queue",
|
"stock_queue",
|
||||||
"section_break_gmim",
|
"section_break_gmim",
|
||||||
"reference_for_reservation"
|
"reference_for_reservation",
|
||||||
|
"voucher_type",
|
||||||
|
"voucher_no",
|
||||||
|
"column_break_eykr",
|
||||||
|
"posting_datetime",
|
||||||
|
"type_of_transaction",
|
||||||
|
"voucher_detail_no"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Valuation Rate",
|
"label": "Valuation Rate",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
|
"non_negative": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"read_only_depends_on": "eval:parent.type_of_transaction == \"Outward\""
|
"read_only_depends_on": "eval:parent.type_of_transaction == \"Outward\""
|
||||||
},
|
},
|
||||||
@@ -134,17 +141,54 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "posting_datetime",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"label": "Posting Datetime",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "voucher_type",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Voucher Type",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "voucher_no",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Voucher No",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "voucher_detail_no",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Voucher Detail No",
|
||||||
|
"read_only": 1,
|
||||||
|
"search_index": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "type_of_transaction",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Type of Transaction",
|
||||||
|
"read_only": 1,
|
||||||
|
"search_index": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_eykr",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2025-01-02 21:51:52.528916",
|
"modified": "2025-11-09 23:28:35.191959",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Serial and Batch Entry",
|
"name": "Serial and Batch Entry",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
|
"row_format": "Dynamic",
|
||||||
"sort_field": "creation",
|
"sort_field": "creation",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"states": []
|
"states": []
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
# import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
@@ -22,12 +22,21 @@ class SerialandBatchEntry(Document):
|
|||||||
parent: DF.Data
|
parent: DF.Data
|
||||||
parentfield: DF.Data
|
parentfield: DF.Data
|
||||||
parenttype: DF.Data
|
parenttype: DF.Data
|
||||||
|
posting_datetime: DF.Datetime | None
|
||||||
qty: DF.Float
|
qty: DF.Float
|
||||||
reference_for_reservation: DF.Data | None
|
reference_for_reservation: DF.Data | None
|
||||||
serial_no: DF.Link | None
|
serial_no: DF.Link | None
|
||||||
stock_queue: DF.SmallText | None
|
stock_queue: DF.SmallText | None
|
||||||
stock_value_difference: DF.Float
|
stock_value_difference: DF.Float
|
||||||
|
type_of_transaction: DF.Data | None
|
||||||
|
voucher_detail_no: DF.Data | None
|
||||||
|
voucher_no: DF.Data | None
|
||||||
|
voucher_type: DF.Data | None
|
||||||
warehouse: DF.Link | None
|
warehouse: DF.Link | None
|
||||||
# end: auto-generated types
|
# end: auto-generated types
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def on_doctype_update():
|
||||||
|
frappe.db.add_index("Serial and Batch Entry", ["warehouse", "batch_no", "posting_datetime"])
|
||||||
|
|||||||
@@ -742,7 +742,7 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
|
|||||||
"Serial and Batch Bundle", self.sle.serial_and_batch_bundle, "total_amount"
|
"Serial and Batch Bundle", self.sle.serial_and_batch_bundle, "total_amount"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
entries = self.get_batch_no_ledgers()
|
entries = self.get_batch_stock_before_date()
|
||||||
self.stock_value_change = 0.0
|
self.stock_value_change = 0.0
|
||||||
self.batch_avg_rate = defaultdict(float)
|
self.batch_avg_rate = defaultdict(float)
|
||||||
self.available_qty = defaultdict(float)
|
self.available_qty = defaultdict(float)
|
||||||
@@ -751,8 +751,9 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
|
|||||||
for ledger in entries:
|
for ledger in entries:
|
||||||
self.stock_value_differece[ledger.batch_no] += flt(ledger.incoming_rate)
|
self.stock_value_differece[ledger.batch_no] += flt(ledger.incoming_rate)
|
||||||
self.available_qty[ledger.batch_no] += flt(ledger.qty)
|
self.available_qty[ledger.batch_no] += flt(ledger.qty)
|
||||||
|
self.total_qty[ledger.batch_no] += flt(ledger.qty)
|
||||||
|
|
||||||
entries = self.get_batch_wise_total_available_qty()
|
entries = self.get_batch_stock_after_date()
|
||||||
for row in entries:
|
for row in entries:
|
||||||
self.total_qty[row.batch_no] += flt(row.total_qty)
|
self.total_qty[row.batch_no] += flt(row.total_qty)
|
||||||
|
|
||||||
@@ -760,29 +761,33 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
|
|||||||
self.calculate_avg_rate_for_non_batchwise_valuation()
|
self.calculate_avg_rate_for_non_batchwise_valuation()
|
||||||
self.set_stock_value_difference()
|
self.set_stock_value_difference()
|
||||||
|
|
||||||
def get_batch_wise_total_available_qty(self) -> list[dict]:
|
def get_batch_stock_after_date(self) -> list[dict]:
|
||||||
# Get total qty of each batch no from Serial and Batch Bundle without checking time condition
|
# Get total qty of each batch no from Serial and Batch Bundle without checking time condition
|
||||||
if not self.batchwise_valuation_batches:
|
if not self.batchwise_valuation_batches:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
parent = frappe.qb.DocType("Serial and Batch Bundle")
|
|
||||||
child = frappe.qb.DocType("Serial and Batch Entry")
|
child = frappe.qb.DocType("Serial and Batch Entry")
|
||||||
|
|
||||||
|
timestamp_condition = ""
|
||||||
|
if self.sle.posting_datetime:
|
||||||
|
timestamp_condition = child.posting_datetime > self.sle.posting_datetime
|
||||||
|
|
||||||
|
if self.sle.creation:
|
||||||
|
timestamp_condition |= (child.posting_datetime == self.sle.posting_datetime) & (
|
||||||
|
child.creation > self.sle.creation
|
||||||
|
)
|
||||||
|
|
||||||
query = (
|
query = (
|
||||||
frappe.qb.from_(parent)
|
frappe.qb.from_(child)
|
||||||
.inner_join(child)
|
|
||||||
.on(parent.name == child.parent)
|
|
||||||
.select(
|
.select(
|
||||||
child.batch_no,
|
child.batch_no,
|
||||||
Sum(child.qty).as_("total_qty"),
|
Sum(child.qty).as_("total_qty"),
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
(parent.warehouse == self.sle.warehouse)
|
(child.warehouse == self.sle.warehouse)
|
||||||
& (parent.item_code == self.sle.item_code)
|
|
||||||
& (child.batch_no.isin(self.batchwise_valuation_batches))
|
& (child.batch_no.isin(self.batchwise_valuation_batches))
|
||||||
& (parent.docstatus == 1)
|
& (child.docstatus == 1)
|
||||||
& (parent.is_cancelled == 0)
|
& (child.type_of_transaction.isin(["Inward", "Outward"]))
|
||||||
& (parent.type_of_transaction.isin(["Inward", "Outward"]))
|
|
||||||
)
|
)
|
||||||
.for_update()
|
.for_update()
|
||||||
.groupby(child.batch_no)
|
.groupby(child.batch_no)
|
||||||
@@ -790,47 +795,45 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
|
|||||||
|
|
||||||
# Important to exclude the current voucher detail no / voucher no to calculate the correct stock value difference
|
# Important to exclude the current voucher detail no / voucher no to calculate the correct stock value difference
|
||||||
if self.sle.voucher_detail_no:
|
if self.sle.voucher_detail_no:
|
||||||
query = query.where(parent.voucher_detail_no != self.sle.voucher_detail_no)
|
query = query.where(child.voucher_detail_no != self.sle.voucher_detail_no)
|
||||||
elif self.sle.voucher_no:
|
elif self.sle.voucher_no:
|
||||||
query = query.where(parent.voucher_no != self.sle.voucher_no)
|
query = query.where(child.voucher_no != self.sle.voucher_no)
|
||||||
|
|
||||||
query = query.where(parent.voucher_type != "Pick List")
|
query = query.where(child.voucher_type != "Pick List")
|
||||||
|
|
||||||
|
if timestamp_condition:
|
||||||
|
query = query.where(timestamp_condition)
|
||||||
|
|
||||||
return query.run(as_dict=True)
|
return query.run(as_dict=True)
|
||||||
|
|
||||||
def get_batch_no_ledgers(self) -> list[dict]:
|
def get_batch_stock_before_date(self) -> list[dict]:
|
||||||
# Get batch wise stock value difference from Serial and Batch Bundle considering time condition
|
# Get batch wise stock value difference from Serial and Batch Bundle considering time condition
|
||||||
if not self.batchwise_valuation_batches:
|
if not self.batchwise_valuation_batches:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
parent = frappe.qb.DocType("Serial and Batch Bundle")
|
|
||||||
child = frappe.qb.DocType("Serial and Batch Entry")
|
child = frappe.qb.DocType("Serial and Batch Entry")
|
||||||
|
|
||||||
timestamp_condition = ""
|
timestamp_condition = ""
|
||||||
if self.sle.posting_datetime:
|
if self.sle.posting_datetime:
|
||||||
timestamp_condition = parent.posting_datetime < self.sle.posting_datetime
|
timestamp_condition = child.posting_datetime < self.sle.posting_datetime
|
||||||
|
|
||||||
if self.sle.creation:
|
if self.sle.creation:
|
||||||
timestamp_condition |= (parent.posting_datetime == self.sle.posting_datetime) & (
|
timestamp_condition |= (child.posting_datetime == self.sle.posting_datetime) & (
|
||||||
parent.creation < self.sle.creation
|
child.creation < self.sle.creation
|
||||||
)
|
)
|
||||||
|
|
||||||
query = (
|
query = (
|
||||||
frappe.qb.from_(parent)
|
frappe.qb.from_(child)
|
||||||
.inner_join(child)
|
|
||||||
.on(parent.name == child.parent)
|
|
||||||
.select(
|
.select(
|
||||||
child.batch_no,
|
child.batch_no,
|
||||||
Sum(child.stock_value_difference).as_("incoming_rate"),
|
Sum(child.stock_value_difference).as_("incoming_rate"),
|
||||||
Sum(child.qty).as_("qty"),
|
Sum(child.qty).as_("qty"),
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
(parent.warehouse == self.sle.warehouse)
|
(child.warehouse == self.sle.warehouse)
|
||||||
& (parent.item_code == self.sle.item_code)
|
|
||||||
& (child.batch_no.isin(self.batchwise_valuation_batches))
|
& (child.batch_no.isin(self.batchwise_valuation_batches))
|
||||||
& (parent.docstatus == 1)
|
& (child.docstatus == 1)
|
||||||
& (parent.is_cancelled == 0)
|
& (child.type_of_transaction.isin(["Inward", "Outward"]))
|
||||||
& (parent.type_of_transaction.isin(["Inward", "Outward"]))
|
|
||||||
)
|
)
|
||||||
.for_update()
|
.for_update()
|
||||||
.groupby(child.batch_no)
|
.groupby(child.batch_no)
|
||||||
@@ -838,11 +841,11 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
|
|||||||
|
|
||||||
# Important to exclude the current voucher detail no / voucher no to calculate the correct stock value difference
|
# Important to exclude the current voucher detail no / voucher no to calculate the correct stock value difference
|
||||||
if self.sle.voucher_detail_no:
|
if self.sle.voucher_detail_no:
|
||||||
query = query.where(parent.voucher_detail_no != self.sle.voucher_detail_no)
|
query = query.where(child.voucher_detail_no != self.sle.voucher_detail_no)
|
||||||
elif self.sle.voucher_no:
|
elif self.sle.voucher_no:
|
||||||
query = query.where(parent.voucher_no != self.sle.voucher_no)
|
query = query.where(child.voucher_no != self.sle.voucher_no)
|
||||||
|
|
||||||
query = query.where(parent.voucher_type != "Pick List")
|
query = query.where(child.voucher_type != "Pick List")
|
||||||
if timestamp_condition:
|
if timestamp_condition:
|
||||||
query = query.where(timestamp_condition)
|
query = query.where(timestamp_condition)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user