diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 6abf1ba96d..b9dfec8821 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -379,6 +379,8 @@ class SalesInvoice(SellingController): msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True) def validate_warehouse(self): + super(SalesInvoice, self).validate_warehouse() + for d in self.get('items'): if not d.warehouse: frappe.throw(_("Warehouse required at Row No {0}").format(d.idx)) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 3700d96f4e..74936dac73 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -19,7 +19,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( this._super(); // this.frm.dashboard.reset(); var allow_receipt = false; - var allow_delivery = false; + var is_drop_ship = false; for (var i in cur_frm.doc.items) { var item = cur_frm.doc.items[i]; @@ -27,16 +27,16 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( allow_receipt = true; } - if(item.delivered_by_supplier === 1) { - allow_delivery = true + else { + is_drop_ship = true } - if(allow_delivery && allow_receipt) { + if(is_drop_ship && allow_receipt) { break; } } - cur_frm.set_df_property("drop_ship", "hidden", !allow_delivery); + cur_frm.set_df_property("drop_ship", "hidden", !is_drop_ship); if(doc.docstatus == 1 && !in_list(["Stopped", "Closed", "Delivered"], doc.status)) { if (this.frm.has_perm("submit")) { @@ -47,7 +47,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( cur_frm.add_custom_button(__('Close'), this.close_purchase_order); } - if(allow_delivery && doc.status!="Delivered"){ + if(is_drop_ship && doc.status!="Delivered"){ cur_frm.add_custom_button(__('Mark as Delivered'), this.delivered_by_supplier); } diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 74fe371627..4670e35af1 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -138,9 +138,11 @@ class PurchaseOrder(BuyingController): """update requested qty (before ordered_qty is updated)""" item_wh_list = [] for d in self.get("items"): - if (not po_item_rows or d.name in po_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \ - and frappe.db.get_value("Item", d.item_code, "is_stock_item") and d.warehouse: - item_wh_list.append([d.item_code, d.warehouse]) + if (not po_item_rows or d.name in po_item_rows) \ + and [d.item_code, d.warehouse] not in item_wh_list \ + and frappe.db.get_value("Item", d.item_code, "is_stock_item") \ + and d.warehouse and not d.delivered_by_supplier: + item_wh_list.append([d.item_code, d.warehouse]) for item_code, warehouse in item_wh_list: update_bin_qty(item_code, warehouse, { @@ -165,7 +167,7 @@ class PurchaseOrder(BuyingController): clear_doctype_notifications(self) def on_submit(self): - if self.is_drop_ship_item(): + if self.has_drop_ship_item(): self.update_status_updater() super(PurchaseOrder, self).on_submit() @@ -182,7 +184,7 @@ class PurchaseOrder(BuyingController): purchase_controller.update_last_purchase_rate(self, is_submit = 1) def on_cancel(self): - if self.is_drop_ship_item(): + if self.has_drop_ship_item(): self.update_status_updater() pc_obj = frappe.get_doc('Purchase Common') @@ -245,7 +247,7 @@ class PurchaseOrder(BuyingController): so.set_status(update=True) so.notify_update() - def is_drop_ship_item(self): + def has_drop_ship_item(self): is_drop_ship = False for item in self.items: diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 5ccf29d503..69561e11df 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -52,15 +52,6 @@ class BuyingController(StockController): self.supplier = supplier break - def validate_warehouse(self): - from erpnext.stock.utils import validate_warehouse_company - - warehouses = list(set([d.warehouse for d in - self.get("items") if getattr(d, "warehouse", None)])) - - for w in warehouses: - validate_warehouse_company(w, self.company) - def validate_stock_or_nonstock_items(self): if self.meta.get_field("taxes") and not self.get_stock_items(): tax_for_valuation = [d.account_head for d in self.get("taxes") diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 2a9fa17061..5deb839e81 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -303,6 +303,15 @@ class StockController(AccountsController): })) self.make_sl_entries(sl_entries) + + def validate_warehouse(self): + from erpnext.stock.utils import validate_warehouse_company + + warehouses = list(set([d.warehouse for d in + self.get("items") if getattr(d, "warehouse", None)])) + + for w in warehouses: + validate_warehouse_company(w, self.company) def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None, warehouse_account=None): diff --git a/erpnext/patches/v6_8/move_drop_ship_to_po_items.py b/erpnext/patches/v6_8/move_drop_ship_to_po_items.py index 8163e8f125..44ba3f0a5d 100644 --- a/erpnext/patches/v6_8/move_drop_ship_to_po_items.py +++ b/erpnext/patches/v6_8/move_drop_ship_to_po_items.py @@ -6,14 +6,14 @@ def execute(): for item in purchase_order.items: if item.prevdoc_doctype == "Sales Order": - delivered_by_supplier = frappe.get_value("Sales Order Item", {"parent": item.prevdoc_docname, - "item_code": item.item_code}, "delivered_by_supplier") + delivered_by_supplier = frappe.get_value("Sales Order Item", item.prevdoc_detail_docname, + "delivered_by_supplier") if delivered_by_supplier: - frappe.db.set_value("Purchase Order Item", item.name, "delivered_by_supplier", 1) - frappe.db.set_value("Purchase Order Item", item.name, "billed_amt", item.amount) - frappe.db.set_value("Purchase Order Item", item.name, "received_qty", item.qty) - + frappe.db.sql("""update `tabPurchase Order Item` + set delivered_by_supplier=1, billed_amt=amount, received_qty=qty + where name=%s """, item.name) + update_per_received(purchase_order) update_per_billed(purchase_order) @@ -22,15 +22,15 @@ def update_per_received(po): set per_received = round((select sum(if(qty > ifnull(received_qty, 0), ifnull(received_qty, 0), qty)) / sum(qty) *100 from `tabPurchase Order Item` - where parent = "%(name)s"), 2) - where name = "%(name)s" """ % po.as_dict()) + where parent = %(name)s), 2) + where name = %(name)s """, {"name": po.name}) def update_per_billed(po): frappe.db.sql(""" update `tabPurchase Order` set per_billed = round((select sum( if(amount > ifnull(billed_amt, 0), ifnull(billed_amt, 0), amount)) / sum(amount) *100 from `tabPurchase Order Item` - where parent = "%(name)s"), 2) - where name = "%(name)s" """ % po.as_dict()) + where parent = %(name)s), 2) + where name = %(name)s """, {"name": po.name}) \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 5ceeea8518..d2b165398d 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -66,12 +66,6 @@ class SalesOrder(SellingController): for d in self.get('items'): check_list.append(cstr(d.item_code)) - if (frappe.db.get_value("Item", d.item_code, "is_stock_item")==1 or - (self.has_product_bundle(d.item_code) and self.product_bundle_has_stock_item(d.item_code))) \ - and not d.warehouse and not cint(d.delivered_by_supplier): - frappe.throw(_("Delivery warehouse required for stock item {0}").format(d.item_code), - WarehouseRequired) - # used for production plan d.transaction_date = self.transaction_date @@ -116,14 +110,15 @@ class SalesOrder(SellingController): frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project_name)) def validate_warehouse(self): - from erpnext.stock.utils import validate_warehouse_company - - warehouses = list(set([d.warehouse for d in - self.get("items") if d.warehouse])) - - for w in warehouses: - validate_warehouse_company(w, self.company) - + super(SalesOrder, self).validate_warehouse() + + for d in self.get("items"): + if (frappe.db.get_value("Item", d.item_code, "is_stock_item")==1 or + (self.has_product_bundle(d.item_code) and self.product_bundle_has_stock_item(d.item_code))) \ + and not d.warehouse and not cint(d.delivered_by_supplier): + frappe.throw(_("Delivery warehouse required for stock item {0}").format(d.item_code), + WarehouseRequired) + def validate_with_previous_doc(self): super(SalesOrder, self).validate_with_previous_doc({ "Quotation": { @@ -236,13 +231,13 @@ class SalesOrder(SellingController): item_wh_list.append([item_code, warehouse]) for d in self.get("items"): - if (not so_item_rows or d.name in so_item_rows): - _valid_for_reserve(d.item_code, d.warehouse) - + if (not so_item_rows or d.name in so_item_rows) and not d.delivered_by_supplier: if self.has_product_bundle(d.item_code): for p in self.get("packed_items"): if p.parent_detail_docname == d.name and p.parent_item == d.item_code: _valid_for_reserve(p.item_code, p.warehouse) + else: + _valid_for_reserve(d.item_code, d.warehouse) for item_code, warehouse in item_wh_list: update_bin_qty(item_code, warehouse, { diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 60cc430c8a..d6532505af 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -170,6 +170,8 @@ class DeliveryNote(SellingController): chk_dupl_itm.append(f) def validate_warehouse(self): + super(DeliveryNote, self).validate_warehouse() + for d in self.get_item_list(): if frappe.db.get_value("Item", d['item_code'], "is_stock_item") == 1: if not d['warehouse']: diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index 609c986c44..87e7fcd82c 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -76,10 +76,12 @@ def get_reserved_qty(item_code, warehouse): ( select qty from `tabSales Order Item` where name = dnpi.parent_detail_docname + and (delivered_by_supplier is null or delivered_by_supplier = 0) ) as so_item_qty, ( select ifnull(delivered_qty, 0) from `tabSales Order Item` - where name = dnpi.parent_detail_docname + where name = dnpi.parent_detail_docname + and (delivered_by_supplier is null or delivered_by_supplier = 0) ) as so_item_delivered_qty, parent, name from @@ -96,7 +98,8 @@ def get_reserved_qty(item_code, warehouse): (select qty as dnpi_qty, qty as so_item_qty, ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name from `tabSales Order Item` so_item - where item_code = %s and warehouse = %s + where item_code = %s and warehouse = %s + and (so_item.delivered_by_supplier is null or so_item.delivered_by_supplier = 0) and exists(select * from `tabSales Order` so where so.name = so_item.parent and so.docstatus = 1 and so.status not in ('Stopped','Closed'))) @@ -122,7 +125,9 @@ def get_ordered_qty(item_code, warehouse): from `tabPurchase Order Item` po_item, `tabPurchase Order` po where po_item.item_code=%s and po_item.warehouse=%s and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name - and po.status not in ('Stopped', 'Closed', 'Delivered') and po.docstatus=1""", (item_code, warehouse)) + and po.status not in ('Stopped', 'Closed', 'Delivered') and po.docstatus=1 + and (po_item.delivered_by_supplier is null or po_item.delivered_by_supplier = 0) + """, (item_code, warehouse)) return flt(ordered_qty[0][0]) if ordered_qty else 0