mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-14 04:15:10 +00:00
feat: change sabb qty automatically incase of internal transfer PR if sabb only has 1 batch (#47256)
* feat: change sabb qty automatically incase of internal transfer PR if sabb only has 1 batch
* fix: prevent creation of SABB on every save
* perf: optimize code
* fix: remove unnecessary conditon
* refactor: change if to elif
* fix: remove dn_item_qty and set to item.qty
* test: added test
(cherry picked from commit 47927b38a9)
This commit is contained in:
@@ -98,7 +98,29 @@ class BuyingController(SubcontractingController):
|
|||||||
item.from_warehouse,
|
item.from_warehouse,
|
||||||
type_of_transaction="Outward",
|
type_of_transaction="Outward",
|
||||||
do_not_submit=True,
|
do_not_submit=True,
|
||||||
|
qty=item.qty,
|
||||||
)
|
)
|
||||||
|
elif (
|
||||||
|
not self.is_new()
|
||||||
|
and item.serial_and_batch_bundle
|
||||||
|
and next(
|
||||||
|
(
|
||||||
|
old_item
|
||||||
|
for old_item in self.get_doc_before_save().items
|
||||||
|
if old_item.name == item.name and old_item.qty != item.qty
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
and len(
|
||||||
|
sabe := frappe.get_all(
|
||||||
|
"Serial and Batch Entry",
|
||||||
|
filters={"parent": item.serial_and_batch_bundle, "serial_no": ["is", "not set"]},
|
||||||
|
pluck="name",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
== 1
|
||||||
|
):
|
||||||
|
frappe.set_value("Serial and Batch Entry", sabe[0], "qty", item.qty)
|
||||||
|
|
||||||
def set_rate_for_standalone_debit_note(self):
|
def set_rate_for_standalone_debit_note(self):
|
||||||
if self.get("is_return") and self.get("update_stock") and not self.return_against:
|
if self.get("is_return") and self.get("update_stock") and not self.return_against:
|
||||||
|
|||||||
@@ -811,7 +811,7 @@ class StockController(AccountsController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def make_package_for_transfer(
|
def make_package_for_transfer(
|
||||||
self, serial_and_batch_bundle, warehouse, type_of_transaction=None, do_not_submit=None
|
self, serial_and_batch_bundle, warehouse, type_of_transaction=None, do_not_submit=None, qty=0
|
||||||
):
|
):
|
||||||
return make_bundle_for_material_transfer(
|
return make_bundle_for_material_transfer(
|
||||||
is_new=self.is_new(),
|
is_new=self.is_new(),
|
||||||
@@ -822,6 +822,7 @@ class StockController(AccountsController):
|
|||||||
warehouse=warehouse,
|
warehouse=warehouse,
|
||||||
type_of_transaction=type_of_transaction,
|
type_of_transaction=type_of_transaction,
|
||||||
do_not_submit=do_not_submit,
|
do_not_submit=do_not_submit,
|
||||||
|
qty=qty,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_sl_entries(self, d, args):
|
def get_sl_entries(self, d, args):
|
||||||
@@ -1815,15 +1816,20 @@ def make_bundle_for_material_transfer(**kwargs):
|
|||||||
kwargs.type_of_transaction = "Inward"
|
kwargs.type_of_transaction = "Inward"
|
||||||
|
|
||||||
bundle_doc = frappe.copy_doc(bundle_doc)
|
bundle_doc = frappe.copy_doc(bundle_doc)
|
||||||
|
bundle_doc.docstatus = 0
|
||||||
bundle_doc.warehouse = kwargs.warehouse
|
bundle_doc.warehouse = kwargs.warehouse
|
||||||
bundle_doc.type_of_transaction = kwargs.type_of_transaction
|
bundle_doc.type_of_transaction = kwargs.type_of_transaction
|
||||||
bundle_doc.voucher_type = kwargs.voucher_type
|
bundle_doc.voucher_type = kwargs.voucher_type
|
||||||
bundle_doc.voucher_no = "" if kwargs.is_new or kwargs.docstatus == 2 else kwargs.voucher_no
|
bundle_doc.voucher_no = "" if kwargs.is_new or kwargs.docstatus == 2 else kwargs.voucher_no
|
||||||
bundle_doc.is_cancelled = 0
|
bundle_doc.is_cancelled = 0
|
||||||
|
|
||||||
|
qty = 0
|
||||||
|
if len(bundle_doc.entries) == 1 and kwargs.qty < bundle_doc.total_qty and not bundle_doc.has_serial_no:
|
||||||
|
qty = kwargs.qty
|
||||||
|
|
||||||
for row in bundle_doc.entries:
|
for row in bundle_doc.entries:
|
||||||
row.is_outward = 0
|
row.is_outward = 0
|
||||||
row.qty = abs(row.qty)
|
row.qty = abs(qty or row.qty)
|
||||||
row.stock_value_difference = abs(row.stock_value_difference)
|
row.stock_value_difference = abs(row.stock_value_difference)
|
||||||
if kwargs.type_of_transaction == "Outward":
|
if kwargs.type_of_transaction == "Outward":
|
||||||
row.qty *= -1
|
row.qty *= -1
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ from frappe.utils import add_days, cint, cstr, flt, get_datetime, getdate, nowti
|
|||||||
from pypika import functions as fn
|
from pypika import functions as fn
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
|
import erpnext.controllers
|
||||||
|
import erpnext.controllers.status_updater
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||||
from erpnext.controllers.buying_controller import QtyMismatchError
|
from erpnext.controllers.buying_controller import QtyMismatchError
|
||||||
@@ -4129,6 +4131,59 @@ class TestPurchaseReceipt(FrappeTestCase):
|
|||||||
|
|
||||||
self.assertTrue(sles)
|
self.assertTrue(sles)
|
||||||
|
|
||||||
|
def test_internal_pr_qty_change_only_single_batch(self):
|
||||||
|
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
|
||||||
|
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||||
|
|
||||||
|
prepare_data_for_internal_transfer()
|
||||||
|
|
||||||
|
def get_sabb_qty(sabb):
|
||||||
|
return frappe.get_value("Serial and Batch Bundle", sabb, "total_qty")
|
||||||
|
|
||||||
|
item = make_item("Item with only Batch", {"has_batch_no": 1})
|
||||||
|
item.create_new_batch = 1
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
make_purchase_receipt(
|
||||||
|
item_code=item.item_code,
|
||||||
|
qty=10,
|
||||||
|
rate=100,
|
||||||
|
company="_Test Company with perpetual inventory",
|
||||||
|
warehouse="Stores - TCP1",
|
||||||
|
)
|
||||||
|
|
||||||
|
dn = create_delivery_note(
|
||||||
|
item_code=item.item_code,
|
||||||
|
qty=10,
|
||||||
|
rate=100,
|
||||||
|
company="_Test Company with perpetual inventory",
|
||||||
|
customer="_Test Internal Customer 2",
|
||||||
|
cost_center="Main - TCP1",
|
||||||
|
warehouse="Stores - TCP1",
|
||||||
|
target_warehouse="Work In Progress - TCP1",
|
||||||
|
)
|
||||||
|
pr = make_inter_company_purchase_receipt(dn.name)
|
||||||
|
|
||||||
|
pr.items[0].warehouse = "Stores - TCP1"
|
||||||
|
pr.items[0].qty = 8
|
||||||
|
pr.save()
|
||||||
|
|
||||||
|
# Test 1 - Check if SABB qty is changed on first save
|
||||||
|
self.assertEqual(abs(get_sabb_qty(pr.items[0].serial_and_batch_bundle)), 8)
|
||||||
|
|
||||||
|
pr.items[0].qty = 6
|
||||||
|
pr.items[0].received_qty = 6
|
||||||
|
pr.save()
|
||||||
|
|
||||||
|
# Test 2 - Check if SABB qty is changed when saved again
|
||||||
|
self.assertEqual(abs(get_sabb_qty(pr.items[0].serial_and_batch_bundle)), 6)
|
||||||
|
|
||||||
|
pr.items[0].qty = 12
|
||||||
|
pr.items[0].received_qty = 12
|
||||||
|
|
||||||
|
# Test 3 - OverAllowanceError should be thrown as qty is greater than qty in DN
|
||||||
|
self.assertRaises(erpnext.controllers.status_updater.OverAllowanceError, pr.submit)
|
||||||
|
|
||||||
|
|
||||||
def prepare_data_for_internal_transfer():
|
def prepare_data_for_internal_transfer():
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
|
||||||
|
|||||||
Reference in New Issue
Block a user