Merge pull request #23645 from rohitwaghchaure/receive-at-warehouse-not-validate-for-extra-transfer-qty

fix: extra material received against send to warehouse entry
This commit is contained in:
rohitwaghchaure
2020-10-15 13:59:45 +05:30
committed by GitHub
2 changed files with 54 additions and 64 deletions

View File

@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe, erpnext
import frappe.defaults
from frappe import _
from frappe.utils import cstr, cint, flt, comma_or, getdate, nowdate, formatdate, format_time
from frappe.utils import cstr, cint, flt, comma_or, getdate, nowdate, formatdate, format_time, get_link_to_form
from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError, get_valuation_rate
from erpnext.stock.get_item_details import get_bin_details, get_default_cost_center, get_conversion_factor, get_reserved_qty_for_so
@@ -27,6 +27,7 @@ class IncorrectValuationRateError(frappe.ValidationError): pass
class DuplicateEntryForWorkOrderError(frappe.ValidationError): pass
class OperationsNotCompleteError(frappe.ValidationError): pass
class MaxSampleAlreadyRetainedError(frappe.ValidationError): pass
class ExtraMaterialReceived(frappe.ValidationError): pass
from erpnext.controllers.stock_controller import StockController
@@ -35,6 +36,11 @@ form_grid_templates = {
}
class StockEntry(StockController):
def __init__(self, *args, **kwargs):
"""To initialize the status updater."""
super(StockEntry, self).__init__(*args, **kwargs)
self.status_updater = []
def get_feed(self):
return self.stock_entry_type
@@ -51,7 +57,6 @@ class StockEntry(StockController):
self.validate_purpose()
self.validate_item()
self.validate_customer_provided_item()
self.validate_qty()
self.set_transfer_qty()
self.validate_uom_is_integer("uom", "qty")
self.validate_uom_is_integer("stock_uom", "transfer_qty")
@@ -122,6 +127,22 @@ class StockEntry(StockController):
self.from_bom = 1
self.bom_no = data.bom_no
def limits_crossed_error(self, args, item, qty_or_amount):
"""To override the method limits_crossed_error which is defined in the status_updater."""
"""Raise the exception for extra material transfer against the send to warehouse."""
send_to_ste = frappe.bold(get_link_to_form("Stock Entry", self.outgoing_stock_entry))
message = _("For more details please check the send to warehouse document {0}.").format(send_to_ste)
frappe.throw(_('For the item {0}, the received quantity {1} is more than the sent quantity {2}. {3}{4}')
.format(
frappe.bold(item.get('item_code')),
frappe.bold((item[args["target_field"]])),
frappe.bold(item[args["target_ref_field"]]),
'<br>',
message
), ExtraMaterialReceived, title = _('Extra Materials Transferred'))
def validate_work_order_status(self):
pro_doc = frappe.get_doc("Work Order", self.work_order)
if pro_doc.status == 'Completed':
@@ -205,33 +226,6 @@ class StockEntry(StockController):
frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
frappe.MandatoryError)
def validate_qty(self):
manufacture_purpose = ["Manufacture", "Material Consumption for Manufacture"]
if self.purpose in manufacture_purpose and self.work_order:
if not frappe.get_value('Work Order', self.work_order, 'skip_transfer'):
item_code = []
for item in self.items:
if cstr(item.t_warehouse) == '':
req_items = frappe.get_all('Work Order Item',
filters={'parent': self.work_order, 'item_code': item.item_code}, fields=["item_code"])
transferred_materials = frappe.db.sql("""
select
sum(qty) as qty
from `tabStock Entry` se,`tabStock Entry Detail` sed
where
se.name = sed.parent and se.docstatus=1 and
(se.purpose='Material Transfer for Manufacture' or se.purpose='Manufacture')
and sed.item_code=%s and se.work_order= %s and ifnull(sed.t_warehouse, '') != ''
""", (item.item_code, self.work_order), as_dict=1)
stock_qty = flt(item.qty)
trans_qty = flt(transferred_materials[0].qty)
if req_items:
if stock_qty > trans_qty:
item_code.append(item.item_code)
def validate_fg_completed_qty(self):
if self.purpose == "Manufacture" and self.work_order:
production_item = frappe.get_value('Work Order', self.work_order, 'production_item')
@@ -1297,37 +1291,7 @@ class StockEntry(StockController):
def update_transferred_qty(self):
if self.purpose == 'Receive at Warehouse':
stock_entries = {}
stock_entries_child_list = []
for d in self.items:
if not (d.against_stock_entry and d.ste_detail):
continue
stock_entries_child_list.append(d.ste_detail)
transferred_qty = frappe.get_all("Stock Entry Detail", fields = ["sum(qty) as qty"],
filters = { 'against_stock_entry': d.against_stock_entry,
'ste_detail': d.ste_detail,'docstatus': 1})
stock_entries[(d.against_stock_entry, d.ste_detail)] = (transferred_qty[0].qty
if transferred_qty and transferred_qty[0] else 0.0) or 0.0
if not stock_entries: return None
cond = ''
for data, transferred_qty in stock_entries.items():
cond += """ WHEN (parent = %s and name = %s) THEN %s
""" %(frappe.db.escape(data[0]), frappe.db.escape(data[1]), transferred_qty)
if cond and stock_entries_child_list:
frappe.db.sql(""" UPDATE `tabStock Entry Detail`
SET
transferred_qty = CASE {cond} END
WHERE
name in ({ste_details}) """.format(cond=cond,
ste_details = ','.join(['%s'] * len(stock_entries_child_list))),
tuple(stock_entries_child_list))
args = {
self.status_updater.append({
'source_dt': 'Stock Entry Detail',
'target_field': 'transferred_qty',
'target_ref_field': 'qty',
@@ -1336,10 +1300,11 @@ class StockEntry(StockController):
'target_parent_dt': 'Stock Entry',
'target_parent_field': 'per_transferred',
'source_field': 'qty',
'percent_join_field': 'against_stock_entry'
}
'percent_join_field': 'against_stock_entry',
'no_allowance': 1
})
self._update_percent_field_in_targets(args, update_modified=True)
self.update_prevdoc_status()
def update_quality_inspection(self):
if self.inspection_required:

View File

@@ -14,7 +14,8 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
from erpnext.stock.doctype.item.test_item import set_item_variant_settings, make_item_variant, create_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.stock.doctype.stock_entry.stock_entry import move_sample_to_retention_warehouse, make_stock_in_entry
from erpnext.stock.doctype.stock_entry.stock_entry import (move_sample_to_retention_warehouse,
make_stock_in_entry, ExtraMaterialReceived)
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from six import iteritems
@@ -871,6 +872,30 @@ class TestStockEntry(unittest.TestCase):
doc = frappe.get_doc('Stock Entry', outward_entry.name)
self.assertEqual(doc.per_transferred, 100)
def test_raise_extra_transfer_materials(self):
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
warehouse = "_Test Warehouse FG 1 - _TC"
if not frappe.db.exists('Warehouse', warehouse):
create_warehouse("_Test Warehouse FG 1")
outward_entry = make_stock_entry(item_code="_Test Item",
purpose="Send to Warehouse",
source="_Test Warehouse - _TC",
target="_Test Warehouse 1 - _TC", qty=50, basic_rate=100)
inward_entry1 = make_stock_in_entry(outward_entry.name)
inward_entry1.items[0].t_warehouse = warehouse
inward_entry1.items[0].qty = 25
inward_entry1.submit()
inward_entry2 = make_stock_in_entry(outward_entry.name)
inward_entry2.items[0].t_warehouse = warehouse
inward_entry2.items[0].qty = 35
self.assertRaises(ExtraMaterialReceived, inward_entry2.submit)
print(inward_entry2.name)
def test_gle_for_opening_stock_entry(self):
mr = make_stock_entry(item_code="_Test Item", target="Stores - TCP1", company="_Test Company with perpetual inventory",qty=50, basic_rate=100, expense_account="Stock Adjustment - TCP1", is_opening="Yes", do_not_save=True)