fix: stock reco test case for serial and batch bundle
This commit is contained in:
parent
f4cfc589c6
commit
42b229435c
@ -88,7 +88,6 @@ class TestAssetRepair(unittest.TestCase):
|
||||
self.assertEqual(stock_entry.items[0].qty, asset_repair.stock_items[0].consumed_quantity)
|
||||
|
||||
def test_serialized_item_consumption(self):
|
||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoRequiredError
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
||||
|
||||
stock_entry = make_serialized_item()
|
||||
|
@ -53,7 +53,6 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'scan_serial_no',
|
||||
label: __('Scan Serial No'),
|
||||
options: 'Serial No',
|
||||
get_query: () => {
|
||||
return {
|
||||
filters: this.get_serial_no_filters()
|
||||
@ -71,10 +70,9 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
|
||||
if (this.item.has_batch_no) {
|
||||
fields.push({
|
||||
fieldtype: 'Link',
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'scan_batch_no',
|
||||
label: __('Scan Batch No'),
|
||||
options: 'Batch',
|
||||
get_query: () => {
|
||||
return {
|
||||
filters: {
|
||||
@ -104,6 +102,8 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
|
||||
if (this.item?.outward) {
|
||||
fields = [...this.get_filter_fields(), ...fields];
|
||||
} else {
|
||||
fields = [...fields, ...this.get_attach_field()];
|
||||
}
|
||||
|
||||
fields.push({
|
||||
@ -121,6 +121,73 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
return fields;
|
||||
}
|
||||
|
||||
get_attach_field() {
|
||||
let label = this.item?.has_serial_no ? __('Serial Nos') : __('Batch Nos');
|
||||
let primary_label = this.bundle
|
||||
? __('Update') : __('Add');
|
||||
|
||||
if (this.item?.has_serial_no && this.item?.has_batch_no) {
|
||||
label = __('Serial Nos / Batch Nos');
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
fieldtype: 'Section Break',
|
||||
label: __('{0} {1} via CSV File', [primary_label, label])
|
||||
},
|
||||
{
|
||||
fieldtype: 'Button',
|
||||
fieldname: 'download_csv',
|
||||
label: __('Download CSV Template'),
|
||||
click: () => this.download_csv_file()
|
||||
},
|
||||
{
|
||||
fieldtype: 'Column Break',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Attach',
|
||||
fieldname: 'attach_serial_batch_csv',
|
||||
label: __('Attach CSV File'),
|
||||
onchange: () => this.upload_csv_file()
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
download_csv_file() {
|
||||
let csvFileData = ['Serial No'];
|
||||
|
||||
if (this.item.has_serial_no && this.item.has_batch_no) {
|
||||
csvFileData = ['Serial No', 'Batch No', 'Quantity'];
|
||||
} else if (this.item.has_batch_no) {
|
||||
csvFileData = ['Batch No', 'Quantity'];
|
||||
}
|
||||
|
||||
const method = `/api/method/erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.download_blank_csv_template?content=${encodeURIComponent(JSON.stringify(csvFileData))}`;
|
||||
const w = window.open(frappe.urllib.get_full_url(method));
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups"));
|
||||
}
|
||||
}
|
||||
|
||||
upload_csv_file() {
|
||||
const file_path = this.dialog.get_value("attach_serial_batch_csv")
|
||||
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.upload_csv_file',
|
||||
args: {
|
||||
item_code: this.item.item_code,
|
||||
file_path: file_path
|
||||
},
|
||||
callback: (r) => {
|
||||
if (r.message.serial_nos && r.message.serial_nos.length) {
|
||||
this.set_data(r.message.serial_nos);
|
||||
} else if (r.message.batch_nos && r.message.batch_nos.length) {
|
||||
this.set_data(r.message.batch_nos);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get_filter_fields() {
|
||||
return [
|
||||
{
|
||||
@ -213,10 +280,6 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate {
|
||||
get_auto_data() {
|
||||
const { qty, based_on } = this.dialog.get_values();
|
||||
|
||||
if (!qty) {
|
||||
frappe.throw(__('Please enter Qty to Fetch'));
|
||||
}
|
||||
|
||||
if (!based_on) {
|
||||
based_on = 'FIFO';
|
||||
}
|
||||
|
@ -168,7 +168,12 @@ class Batch(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_batch_qty(
|
||||
batch_no=None, warehouse=None, item_code=None, posting_date=None, posting_time=None
|
||||
batch_no=None,
|
||||
warehouse=None,
|
||||
item_code=None,
|
||||
posting_date=None,
|
||||
posting_time=None,
|
||||
ignore_voucher_nos=None,
|
||||
):
|
||||
"""Returns batch actual qty if warehouse is passed,
|
||||
or returns dict of qty by warehouse if warehouse is None
|
||||
@ -191,6 +196,7 @@ def get_batch_qty(
|
||||
"posting_date": posting_date,
|
||||
"posting_time": posting_time,
|
||||
"batch_no": batch_no,
|
||||
"ignore_voucher_nos": ignore_voucher_nos,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -21,6 +21,7 @@ from frappe.utils import (
|
||||
parse_json,
|
||||
today,
|
||||
)
|
||||
from frappe.utils.csvutils import build_csv_response
|
||||
|
||||
from erpnext.stock.serial_batch_bundle import BatchNoValuation, SerialNoValuation
|
||||
from erpnext.stock.serial_batch_bundle import get_serial_nos as get_serial_nos_from_bundle
|
||||
@ -152,15 +153,15 @@ class SerialandBatchBundle(Document):
|
||||
if self.has_serial_no:
|
||||
sn_obj = SerialNoValuation(
|
||||
sle=sle,
|
||||
warehouse=self.item_code,
|
||||
item_code=self.warehouse,
|
||||
item_code=self.item_code,
|
||||
warehouse=self.warehouse,
|
||||
)
|
||||
|
||||
else:
|
||||
sn_obj = BatchNoValuation(
|
||||
sle=sle,
|
||||
warehouse=self.item_code,
|
||||
item_code=self.warehouse,
|
||||
item_code=self.item_code,
|
||||
warehouse=self.warehouse,
|
||||
)
|
||||
|
||||
for d in self.entries:
|
||||
@ -657,6 +658,31 @@ class SerialandBatchBundle(Document):
|
||||
self.set("entries", batch_nos)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def download_blank_csv_template(content):
|
||||
csv_data = []
|
||||
if isinstance(content, str):
|
||||
content = parse_json(content)
|
||||
|
||||
csv_data.append(content)
|
||||
csv_data.append([])
|
||||
csv_data.append([])
|
||||
|
||||
filename = "serial_and_batch_bundle"
|
||||
build_csv_response(csv_data, filename)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def upload_csv_file(item_code, file_path):
|
||||
serial_nos, batch_nos = [], []
|
||||
serial_nos, batch_nos = get_serial_batch_from_csv(item_code, file_path)
|
||||
|
||||
return {
|
||||
"serial_nos": serial_nos,
|
||||
"batch_nos": batch_nos,
|
||||
}
|
||||
|
||||
|
||||
def get_serial_batch_from_csv(item_code, file_path):
|
||||
file_path = frappe.get_site_path() + file_path
|
||||
serial_nos = []
|
||||
@ -669,7 +695,6 @@ def get_serial_batch_from_csv(item_code, file_path):
|
||||
if serial_nos:
|
||||
make_serial_nos(item_code, serial_nos)
|
||||
|
||||
print(batch_nos)
|
||||
if batch_nos:
|
||||
make_batch_nos(item_code, batch_nos)
|
||||
|
||||
@ -938,7 +963,7 @@ def update_serial_batch_no_ledgers(entries, child_row, parent_doc) -> object:
|
||||
doc.append(
|
||||
"entries",
|
||||
{
|
||||
"qty": 1 if doc.type_of_transaction == "Inward" else -1,
|
||||
"qty": d.get("qty") * (1 if doc.type_of_transaction == "Inward" else -1),
|
||||
"warehouse": d.get("warehouse"),
|
||||
"batch_no": d.get("batch_no"),
|
||||
"serial_no": d.get("serial_no"),
|
||||
@ -1272,6 +1297,9 @@ def get_available_batches(kwargs):
|
||||
else:
|
||||
query = query.orderby(batch_table.creation)
|
||||
|
||||
if kwargs.get("ignore_voucher_nos"):
|
||||
query = query.where(stock_ledger_entry.voucher_no.notin(kwargs.get("ignore_voucher_nos")))
|
||||
|
||||
data = query.run(as_dict=True)
|
||||
data = list(filter(lambda x: x.qty > 0, data))
|
||||
|
||||
|
@ -8,7 +8,41 @@ from erpnext.stock.serial_batch_bundle import get_batch_nos, get_serial_nos
|
||||
|
||||
|
||||
class TestSerialandBatchBundle(FrappeTestCase):
|
||||
pass
|
||||
def test_inward_serial_batch_bundle(self):
|
||||
pass
|
||||
|
||||
def test_outward_serial_batch_bundle(self):
|
||||
pass
|
||||
|
||||
def test_old_batch_valuation(self):
|
||||
pass
|
||||
|
||||
def test_old_batch_batchwise_valuation(self):
|
||||
pass
|
||||
|
||||
def test_old_serial_no_valuation(self):
|
||||
pass
|
||||
|
||||
def test_batch_not_belong_to_serial_no(self):
|
||||
pass
|
||||
|
||||
def test_serial_no_not_exists(self):
|
||||
pass
|
||||
|
||||
def test_serial_no_item(self):
|
||||
pass
|
||||
|
||||
def test_serial_no_not_required(self):
|
||||
pass
|
||||
|
||||
def test_serial_no_required(self):
|
||||
pass
|
||||
|
||||
def test_batch_no_not_required(self):
|
||||
pass
|
||||
|
||||
def test_batch_no_required(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_batch_from_bundle(bundle):
|
||||
|
@ -22,38 +22,10 @@ class SerialNoCannotCannotChangeError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNoNotRequiredError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNoRequiredError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNoQtyError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNoItemError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNoWarehouseError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNoBatchError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNoNotExistsError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNoDuplicateError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SerialNo(StockController):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SerialNo, self).__init__(*args, **kwargs)
|
||||
@ -69,6 +41,15 @@ class SerialNo(StockController):
|
||||
)
|
||||
|
||||
self.set_maintenance_status()
|
||||
self.validate_warehouse()
|
||||
|
||||
def validate_warehouse(self):
|
||||
if not self.get("__islocal"):
|
||||
item_code, warehouse = frappe.db.get_value("Serial No", self.name, ["item_code", "warehouse"])
|
||||
if not self.via_stock_ledger and item_code != self.item_code:
|
||||
frappe.throw(_("Item Code cannot be changed for Serial No."), SerialNoCannotCannotChangeError)
|
||||
if not self.via_stock_ledger and warehouse != self.warehouse:
|
||||
frappe.throw(_("Warehouse cannot be changed for Serial No."), SerialNoCannotCannotChangeError)
|
||||
|
||||
def set_maintenance_status(self):
|
||||
if not self.warranty_expiry_date and not self.amc_expiry_date:
|
||||
|
@ -744,8 +744,11 @@ frappe.ui.form.on('Stock Entry Detail', {
|
||||
no_batch_serial_number_value = !d.batch_no;
|
||||
}
|
||||
|
||||
if (no_batch_serial_number_value && !frappe.flags.hide_serial_batch_dialog) {
|
||||
if (no_batch_serial_number_value && !frappe.flags.hide_serial_batch_dialog && !frappe.flags.dialog_set) {
|
||||
frappe.flags.dialog_set = true;
|
||||
erpnext.stock.select_batch_and_serial_no(frm, d);
|
||||
} else {
|
||||
frappe.flags.dialog_set = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,21 +181,25 @@ class StockReconciliation(StockController):
|
||||
bundle_doc.flags.ignore_permissions = True
|
||||
bundle_doc.save()
|
||||
item.serial_and_batch_bundle = bundle_doc.name
|
||||
elif item.serial_and_batch_bundle:
|
||||
pass
|
||||
elif item.serial_and_batch_bundle and not item.qty and not item.valuation_rate:
|
||||
bundle_doc = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle)
|
||||
|
||||
item.qty = bundle_doc.total_qty
|
||||
item.valuation_rate = bundle_doc.avg_rate
|
||||
|
||||
def remove_items_with_no_change(self):
|
||||
"""Remove items if qty or rate is not changed"""
|
||||
self.difference_amount = 0.0
|
||||
|
||||
def _changed(item):
|
||||
if item.current_serial_and_batch_bundle:
|
||||
self.calculate_difference_amount(item, frappe._dict({}))
|
||||
return True
|
||||
|
||||
item_dict = get_stock_balance_for(
|
||||
item.item_code, item.warehouse, self.posting_date, self.posting_time, batch_no=item.batch_no
|
||||
)
|
||||
|
||||
if item.current_serial_and_batch_bundle:
|
||||
return True
|
||||
|
||||
if (item.qty is None or item.qty == item_dict.get("qty")) and (
|
||||
item.valuation_rate is None or item.valuation_rate == item_dict.get("rate")
|
||||
):
|
||||
@ -210,11 +214,7 @@ class StockReconciliation(StockController):
|
||||
|
||||
item.current_qty = item_dict.get("qty")
|
||||
item.current_valuation_rate = item_dict.get("rate")
|
||||
self.difference_amount += flt(item.qty, item.precision("qty")) * flt(
|
||||
item.valuation_rate or item_dict.get("rate"), item.precision("valuation_rate")
|
||||
) - flt(item_dict.get("qty"), item.precision("qty")) * flt(
|
||||
item_dict.get("rate"), item.precision("valuation_rate")
|
||||
)
|
||||
self.calculate_difference_amount(item, item_dict)
|
||||
return True
|
||||
|
||||
items = list(filter(lambda d: _changed(d), self.items))
|
||||
@ -231,6 +231,13 @@ class StockReconciliation(StockController):
|
||||
item.idx = i + 1
|
||||
frappe.msgprint(_("Removed items with no change in quantity or value."))
|
||||
|
||||
def calculate_difference_amount(self, item, item_dict):
|
||||
self.difference_amount += flt(item.qty, item.precision("qty")) * flt(
|
||||
item.valuation_rate or item_dict.get("rate"), item.precision("valuation_rate")
|
||||
) - flt(item_dict.get("qty"), item.precision("qty")) * flt(
|
||||
item_dict.get("rate"), item.precision("valuation_rate")
|
||||
)
|
||||
|
||||
def validate_data(self):
|
||||
def _get_msg(row_num, msg):
|
||||
return _("Row # {0}:").format(row_num + 1) + " " + msg
|
||||
@ -643,7 +650,14 @@ class StockReconciliation(StockController):
|
||||
|
||||
sl_entries = []
|
||||
for row in self.items:
|
||||
if not (row.item_code == item_code and row.batch_no == batch_no):
|
||||
if (
|
||||
not (row.item_code == item_code and row.batch_no == batch_no)
|
||||
and not row.serial_and_batch_bundle
|
||||
):
|
||||
continue
|
||||
|
||||
if row.current_serial_and_batch_bundle:
|
||||
self.recalculate_qty_for_serial_and_batch_bundle(row)
|
||||
continue
|
||||
|
||||
current_qty = get_batch_qty_for_stock_reco(
|
||||
@ -677,6 +691,27 @@ class StockReconciliation(StockController):
|
||||
if sl_entries:
|
||||
self.make_sl_entries(sl_entries)
|
||||
|
||||
def recalculate_qty_for_serial_and_batch_bundle(self, row):
|
||||
doc = frappe.get_doc("Serial and Batch Bundle", row.current_serial_and_batch_bundle)
|
||||
precision = doc.entries[0].precision("qty")
|
||||
|
||||
for d in doc.entries:
|
||||
qty = (
|
||||
get_batch_qty(
|
||||
d.batch_no,
|
||||
doc.warehouse,
|
||||
posting_date=doc.posting_date,
|
||||
posting_time=doc.posting_time,
|
||||
ignore_voucher_nos=[doc.voucher_no],
|
||||
)
|
||||
or 0
|
||||
) * -1
|
||||
|
||||
if flt(d.qty, precision) == flt(qty, precision):
|
||||
continue
|
||||
|
||||
d.db_set("qty", qty)
|
||||
|
||||
|
||||
def get_batch_qty_for_stock_reco(
|
||||
item_code, warehouse, batch_no, posting_date, posting_time, voucher_no
|
||||
|
@ -694,10 +694,12 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
||||
item_code=item_code, posting_time="09:00:00", target=warehouse, qty=100, basic_rate=700
|
||||
)
|
||||
|
||||
batch_no = get_batch_from_bundle(se1.items[0].serial_and_batch_bundle)
|
||||
|
||||
# Removed 50 Qty, Balace Qty 50
|
||||
se2 = make_stock_entry(
|
||||
item_code=item_code,
|
||||
batch_no=se1.items[0].batch_no,
|
||||
batch_no=batch_no,
|
||||
posting_time="10:00:00",
|
||||
source=warehouse,
|
||||
qty=50,
|
||||
@ -709,15 +711,23 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
||||
item_code=item_code,
|
||||
posting_time="11:00:00",
|
||||
warehouse=warehouse,
|
||||
batch_no=se1.items[0].batch_no,
|
||||
batch_no=batch_no,
|
||||
qty=100,
|
||||
rate=100,
|
||||
)
|
||||
|
||||
sle = frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={"is_cancelled": 0, "voucher_no": stock_reco.name, "actual_qty": ("<", 0)},
|
||||
fields=["actual_qty"],
|
||||
)
|
||||
|
||||
self.assertEqual(flt(sle[0].actual_qty), flt(-50.0))
|
||||
|
||||
# Removed 50 Qty, Balace Qty 50
|
||||
make_stock_entry(
|
||||
item_code=item_code,
|
||||
batch_no=se1.items[0].batch_no,
|
||||
batch_no=batch_no,
|
||||
posting_time="12:00:00",
|
||||
source=warehouse,
|
||||
qty=50,
|
||||
@ -741,12 +751,20 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
||||
sle = frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={"item_code": item_code, "warehouse": warehouse, "is_cancelled": 0},
|
||||
fields=["qty_after_transaction"],
|
||||
fields=["qty_after_transaction", "actual_qty", "voucher_type", "voucher_no"],
|
||||
order_by="posting_time desc, creation desc",
|
||||
)
|
||||
|
||||
self.assertEqual(flt(sle[0].qty_after_transaction), flt(50.0))
|
||||
|
||||
sle = frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={"is_cancelled": 0, "voucher_no": stock_reco.name, "actual_qty": ("<", 0)},
|
||||
fields=["actual_qty"],
|
||||
)
|
||||
|
||||
self.assertEqual(flt(sle[0].actual_qty), flt(-100.0))
|
||||
|
||||
def test_update_stock_reconciliation_while_reposting(self):
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
|
||||
@ -914,7 +932,7 @@ def create_stock_reconciliation(**args):
|
||||
"do_not_submit": True,
|
||||
}
|
||||
)
|
||||
)
|
||||
).name
|
||||
|
||||
sr.append(
|
||||
"items",
|
||||
|
@ -17,6 +17,7 @@
|
||||
"amount",
|
||||
"allow_zero_valuation_rate",
|
||||
"serial_no_and_batch_section",
|
||||
"add_serial_batch_bundle",
|
||||
"serial_and_batch_bundle",
|
||||
"batch_no",
|
||||
"column_break_11",
|
||||
@ -203,11 +204,16 @@
|
||||
"label": "Current Serial / Batch Bundle",
|
||||
"options": "Serial and Batch Bundle",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "add_serial_batch_bundle",
|
||||
"fieldtype": "Button",
|
||||
"label": "Add Serial / Batch No"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2023-05-09 18:42:19.224916",
|
||||
"modified": "2023-05-27 17:35:31.026852",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock Reconciliation Item",
|
||||
|
@ -78,6 +78,12 @@ class SerialBatchBundle:
|
||||
|
||||
self.set_serial_and_batch_bundle(sn_doc)
|
||||
|
||||
def validate_actual_qty(self, sn_doc):
|
||||
precision = sn_doc.precision("total_qty")
|
||||
if flt(sn_doc.total_qty, precision) != flt(self.sle.actual_qty, precision):
|
||||
msg = f"Total qty {flt(sn_doc.total_qty, precision)} of Serial and Batch Bundle {sn_doc.name} is not equal to Actual Qty {flt(self.sle.actual_qty, precision)} in the {self.sle.voucher_type} {self.sle.voucher_no}"
|
||||
frappe.throw(_(msg))
|
||||
|
||||
def validate_item(self):
|
||||
msg = ""
|
||||
if self.sle.actual_qty > 0:
|
||||
@ -214,6 +220,8 @@ class SerialBatchBundle:
|
||||
|
||||
def submit_serial_and_batch_bundle(self):
|
||||
doc = frappe.get_doc("Serial and Batch Bundle", self.sle.serial_and_batch_bundle)
|
||||
self.validate_actual_qty(doc)
|
||||
|
||||
doc.flags.ignore_voucher_validation = True
|
||||
doc.submit()
|
||||
|
||||
@ -426,9 +434,6 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
|
||||
)
|
||||
else:
|
||||
entries = self.get_batch_no_ledgers()
|
||||
if frappe.flags.add_breakpoint:
|
||||
breakpoint()
|
||||
|
||||
self.batch_avg_rate = defaultdict(float)
|
||||
self.available_qty = defaultdict(float)
|
||||
self.stock_value_differece = defaultdict(float)
|
||||
|
@ -676,7 +676,7 @@ class update_entries_after(object):
|
||||
|
||||
if (
|
||||
sle.voucher_type == "Stock Reconciliation"
|
||||
and sle.batch_no
|
||||
and (sle.batch_no or (sle.has_batch_no and sle.serial_and_batch_bundle))
|
||||
and sle.voucher_detail_no
|
||||
and sle.actual_qty < 0
|
||||
):
|
||||
@ -734,9 +734,17 @@ class update_entries_after(object):
|
||||
self.update_outgoing_rate_on_transaction(sle)
|
||||
|
||||
def reset_actual_qty_for_stock_reco(self, sle):
|
||||
current_qty = frappe.get_cached_value(
|
||||
"Stock Reconciliation Item", sle.voucher_detail_no, "current_qty"
|
||||
)
|
||||
if sle.serial_and_batch_bundle:
|
||||
current_qty = frappe.get_cached_value(
|
||||
"Serial and Batch Bundle", sle.serial_and_batch_bundle, "total_qty"
|
||||
)
|
||||
|
||||
if current_qty is not None:
|
||||
current_qty = abs(current_qty)
|
||||
else:
|
||||
current_qty = frappe.get_cached_value(
|
||||
"Stock Reconciliation Item", sle.voucher_detail_no, "current_qty"
|
||||
)
|
||||
|
||||
if current_qty:
|
||||
sle.actual_qty = current_qty * -1
|
||||
@ -1524,7 +1532,7 @@ def update_qty_in_future_sle(args, allow_negative_stock=False):
|
||||
next_stock_reco_detail = get_next_stock_reco(args)
|
||||
if next_stock_reco_detail:
|
||||
detail = next_stock_reco_detail[0]
|
||||
if detail.batch_no:
|
||||
if detail.batch_no or (detail.serial_and_batch_bundle and detail.has_batch_no):
|
||||
regenerate_sle_for_batch_stock_reco(detail)
|
||||
|
||||
# add condition to update SLEs before this date & time
|
||||
@ -1602,7 +1610,9 @@ def get_next_stock_reco(kwargs):
|
||||
sle.voucher_no,
|
||||
sle.item_code,
|
||||
sle.batch_no,
|
||||
sle.serial_and_batch_bundle,
|
||||
sle.actual_qty,
|
||||
sle.has_batch_no,
|
||||
)
|
||||
.where(
|
||||
(sle.item_code == kwargs.get("item_code"))
|
||||
|
Loading…
x
Reference in New Issue
Block a user