mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 12:19:12 +00:00
[fix] #8427
This commit is contained in:
@@ -13,7 +13,7 @@ from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty
|
|||||||
from frappe.desk.notifications import clear_doctype_notifications
|
from frappe.desk.notifications import clear_doctype_notifications
|
||||||
from erpnext.buying.utils import (validate_for_items, check_for_closed_status,
|
from erpnext.buying.utils import (validate_for_items, check_for_closed_status,
|
||||||
update_last_purchase_rate)
|
update_last_purchase_rate)
|
||||||
|
from erpnext.stock.utils import get_bin
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@@ -187,6 +187,8 @@ class PurchaseOrder(BuyingController):
|
|||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.update_requested_qty()
|
self.update_requested_qty()
|
||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
|
if self.is_subcontracted == "Yes":
|
||||||
|
self.update_reserved_qty_for_subcontract()
|
||||||
|
|
||||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||||
self.company, self.base_grand_total)
|
self.company, self.base_grand_total)
|
||||||
@@ -249,6 +251,17 @@ class PurchaseOrder(BuyingController):
|
|||||||
if item.delivered_by_supplier == 1:
|
if item.delivered_by_supplier == 1:
|
||||||
item.received_qty = item.qty
|
item.received_qty = item.qty
|
||||||
|
|
||||||
|
def update_reserved_qty_for_subcontract(self):
|
||||||
|
items = list(set([d.rm_item_code for d in self.get("supplied_items")]))
|
||||||
|
item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse
|
||||||
|
from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items))
|
||||||
|
|
||||||
|
for d in self.supplied_items:
|
||||||
|
if d.rm_item_code:
|
||||||
|
warehouse = item_wh.get(d.rm_item_code)
|
||||||
|
stock_bin = get_bin(d.rm_item_code, warehouse)
|
||||||
|
stock_bin.update_reserved_qty_for_sub_contracting(self.name, transferred_qty=0, transaction_type = "Reserve")
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def close_or_unclose_purchase_orders(names, status):
|
def close_or_unclose_purchase_orders(names, status):
|
||||||
if not frappe.has_permission("Purchase Order", "write"):
|
if not frappe.has_permission("Purchase Order", "write"):
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ erpnext.stock.ItemDashboard = Class.extend({
|
|||||||
data.forEach(function(d) {
|
data.forEach(function(d) {
|
||||||
d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production;
|
d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production;
|
||||||
d.pending_qty = 0;
|
d.pending_qty = 0;
|
||||||
d.total_reserved = d.reserved_qty + d.reserved_qty_for_production;
|
d.total_reserved = d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract;
|
||||||
if(d.actual_or_pending > d.actual_qty) {
|
if(d.actual_or_pending > d.actual_qty) {
|
||||||
d.pending_qty = d.actual_or_pending - d.actual_qty;
|
d.pending_qty = d.actual_or_pending - d.actual_qty;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,13 +26,14 @@ def get_data(item_code=None, warehouse=None, item_group=None,
|
|||||||
return frappe.db.sql('''
|
return frappe.db.sql('''
|
||||||
select
|
select
|
||||||
b.item_code, b.warehouse, b.projected_qty, b.reserved_qty,
|
b.item_code, b.warehouse, b.projected_qty, b.reserved_qty,
|
||||||
b.reserved_qty_for_production, b.actual_qty, b.valuation_rate, i.item_name
|
b.reserved_qty_for_production, b.reserved_qty_for_sub_contract, b.actual_qty, b.valuation_rate, i.item_name
|
||||||
from
|
from
|
||||||
tabBin b, tabItem i
|
tabBin b, tabItem i
|
||||||
where
|
where
|
||||||
b.item_code = i.name
|
b.item_code = i.name
|
||||||
and
|
and
|
||||||
(b.projected_qty != 0 or b.reserved_qty != 0 or b.reserved_qty_for_production != 0 or b.actual_qty != 0)
|
(b.projected_qty != 0 or b.reserved_qty != 0 or b.reserved_qty_for_production != 0
|
||||||
|
or b.reserved_qty_for_sub_contract != 0 or b.actual_qty != 0)
|
||||||
{conditions}
|
{conditions}
|
||||||
order by
|
order by
|
||||||
{sort_by} {sort_order}
|
{sort_by} {sort_order}
|
||||||
|
|||||||
@@ -296,6 +296,36 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "reserved_qty_for_sub_contract",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Reserved Qty for sub contract",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@@ -463,7 +493,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-06-13 13:06:32.601505",
|
"modified": "2017-11-22 08:14:30.615638",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Bin",
|
"name": "Bin",
|
||||||
|
|||||||
@@ -94,6 +94,28 @@ class Bin(Document):
|
|||||||
self.db_set('reserved_qty_for_production', self.reserved_qty_for_production)
|
self.db_set('reserved_qty_for_production', self.reserved_qty_for_production)
|
||||||
self.db_set('projected_qty', self.projected_qty)
|
self.db_set('projected_qty', self.projected_qty)
|
||||||
|
|
||||||
|
def update_reserved_qty_for_sub_contracting(self, po_name, transferred_qty, transaction_type):
|
||||||
|
#Update Reserved Quantity for Sub Contracting in Bin
|
||||||
|
if transaction_type == "Reserve":
|
||||||
|
required_qty = frappe.db.sql('''select sum(itemsup.required_qty)
|
||||||
|
from `tabItem` item, `tabPurchase Order` po, `tabPurchase Order Item Supplied` itemsup
|
||||||
|
where
|
||||||
|
item.name = itemsup.rm_item_code
|
||||||
|
and po.name = %s
|
||||||
|
and itemsup.rm_item_code = %s
|
||||||
|
and itemsup.parent = po.name
|
||||||
|
and po.docstatus = 1
|
||||||
|
and po.is_subcontracted = 'Yes'
|
||||||
|
and item.default_warehouse = %s''', (po_name, self.item_code, self.warehouse))[0][0]
|
||||||
|
elif transaction_type == "Transfer":
|
||||||
|
required_qty = 0
|
||||||
|
|
||||||
|
reserved_qty_bin = self.reserved_qty_for_sub_contract
|
||||||
|
reserved_qty_for_sub_contract = reserved_qty_bin + required_qty - transferred_qty
|
||||||
|
|
||||||
|
self.set_projected_qty()
|
||||||
|
self.db_set('reserved_qty_for_sub_contract', reserved_qty_for_sub_contract)
|
||||||
|
self.db_set('projected_qty', self.projected_qty)
|
||||||
|
|
||||||
def update_item_projected_qty(item_code):
|
def update_item_projected_qty(item_code):
|
||||||
'''Set total_projected_qty in Item as sum of projected qty in all warehouses'''
|
'''Set total_projected_qty in Item as sum of projected qty in all warehouses'''
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError
|
|||||||
from erpnext.stock.get_item_details import get_bin_details, get_default_cost_center, get_conversion_factor
|
from erpnext.stock.get_item_details import get_bin_details, get_default_cost_center, get_conversion_factor
|
||||||
from erpnext.stock.doctype.batch.batch import get_batch_no, set_batch_nos
|
from erpnext.stock.doctype.batch.batch import get_batch_no, set_batch_nos
|
||||||
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
|
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
|
||||||
|
from erpnext.stock.utils import get_bin
|
||||||
import json
|
import json
|
||||||
|
|
||||||
class IncorrectValuationRateError(frappe.ValidationError): pass
|
class IncorrectValuationRateError(frappe.ValidationError): pass
|
||||||
@@ -64,6 +65,8 @@ class StockEntry(StockController):
|
|||||||
update_serial_nos_after_submit(self, "items")
|
update_serial_nos_after_submit(self, "items")
|
||||||
self.update_production_order()
|
self.update_production_order()
|
||||||
self.validate_purchase_order()
|
self.validate_purchase_order()
|
||||||
|
if self.purchase_order and self.purpose == "Subcontract":
|
||||||
|
self.update_purchase_order_supplied_items()
|
||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
@@ -803,6 +806,30 @@ class StockEntry(StockController):
|
|||||||
if getdate(self.posting_date) > getdate(expiry_date):
|
if getdate(self.posting_date) > getdate(expiry_date):
|
||||||
frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code))
|
frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code))
|
||||||
|
|
||||||
|
def update_purchase_order_supplied_items(self):
|
||||||
|
materials_transferred = frappe._dict(frappe.db.sql("""
|
||||||
|
select
|
||||||
|
concat(item_code, sed.s_warehouse), sum(qty)
|
||||||
|
from
|
||||||
|
`tabStock Entry` se, `tabStock Entry Detail` sed
|
||||||
|
where
|
||||||
|
se.name = sed.parent and se.docstatus=1 and se.purpose='Subcontract'
|
||||||
|
and se.purchase_order= %s and ifnull(sed.s_warehouse, '') != ''
|
||||||
|
group by sed.item_code, sed.s_warehouse
|
||||||
|
""", self.purchase_order))
|
||||||
|
#Get PO Supplied Items Details
|
||||||
|
po_doc = frappe.get_doc("Purchase Order",self.purchase_order)
|
||||||
|
po_supplied_items = po_doc.get("supplied_items")
|
||||||
|
items = list(set([d.rm_item_code for d in po_supplied_items]))
|
||||||
|
item_wh = frappe._dict(frappe.db.sql("""select item_code as "item_code", default_warehouse as "warehouse"
|
||||||
|
from tabItem where name in ({0})""".format(", ".join(["%s"] * len(items))), items))
|
||||||
|
#Update reserved sub contracted quantity in bin based on Supplied Item Details
|
||||||
|
for d in po_supplied_items:
|
||||||
|
warehouse = item_wh.get(d.rm_item_code)
|
||||||
|
transferred_qty = materials_transferred.get(d.rm_item_code + warehouse)
|
||||||
|
stock_bin = get_bin(d.rm_item_code, warehouse)
|
||||||
|
stock_bin.update_reserved_qty_for_sub_contracting(self.purchase_order, transferred_qty, transaction_type = "Transfer")
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_production_order_details(production_order):
|
def get_production_order_details(production_order):
|
||||||
production_order = frappe.get_doc("Production Order", production_order)
|
production_order = frappe.get_doc("Production Order", production_order)
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ frappe.pages['stock-balance'].on_page_load = function(wrapper) {
|
|||||||
{fieldname: 'projected_qty', label: __('Projected qty')},
|
{fieldname: 'projected_qty', label: __('Projected qty')},
|
||||||
{fieldname: 'reserved_qty', label: __('Reserved for sale')},
|
{fieldname: 'reserved_qty', label: __('Reserved for sale')},
|
||||||
{fieldname: 'reserved_qty_for_production', label: __('Reserved for manufacturing')},
|
{fieldname: 'reserved_qty_for_production', label: __('Reserved for manufacturing')},
|
||||||
|
{fieldname: 'reserved_qty_for_sub_contract', label: __('Reserved for sub contracting')},
|
||||||
{fieldname: 'actual_qty', label: __('Actual qty in stock')},
|
{fieldname: 'actual_qty', label: __('Actual qty in stock')},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ def update_bin_qty(item_code, warehouse, qty_dict=None):
|
|||||||
if mismatch:
|
if mismatch:
|
||||||
bin.projected_qty = (flt(bin.actual_qty) + flt(bin.ordered_qty) +
|
bin.projected_qty = (flt(bin.actual_qty) + flt(bin.ordered_qty) +
|
||||||
flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty)
|
flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty)
|
||||||
- flt(bin.reserved_qty_for_production))
|
- flt(bin.reserved_qty_for_production)) - flt(bin.reserved_qty_for_sub_contract)
|
||||||
|
|
||||||
bin.save()
|
bin.save()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user