Merge pull request #16941 from Mangesh-Khairnar/po-on-hold

Feature: Purchase order on hold
This commit is contained in:
Faris Ansari 2019-04-11 15:36:54 +05:30 committed by GitHub
commit 6472ed2c1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 4081 additions and 4011 deletions

View File

@ -96,7 +96,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
}, },
get_query_filters: { get_query_filters: {
docstatus: 1, docstatus: 1,
status: ["!=", "Closed"], status: ["not in", ["Closed", "On Hold"]],
per_billed: ["<", 99.99], per_billed: ["<", 99.99],
company: me.frm.doc.company company: me.frm.doc.company
} }

View File

@ -16,7 +16,7 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_bille
from erpnext.stock import get_warehouse_account_map from erpnext.stock import get_warehouse_account_map
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
from erpnext.buying.utils import check_for_closed_status from erpnext.buying.utils import check_on_hold_or_closed_status
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
@ -89,7 +89,7 @@ class PurchaseInvoice(BuyingController):
self.check_conversion_rate() self.check_conversion_rate()
self.validate_credit_to_acc() self.validate_credit_to_acc()
self.clear_unallocated_advances("Purchase Invoice Advance", "advances") self.clear_unallocated_advances("Purchase Invoice Advance", "advances")
self.check_for_closed_status() self.check_on_hold_or_closed_status()
self.validate_with_previous_doc() self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("uom", "qty")
self.validate_uom_is_integer("stock_uom", "stock_qty") self.validate_uom_is_integer("stock_uom", "stock_qty")
@ -152,13 +152,13 @@ class PurchaseInvoice(BuyingController):
self.party_account_currency = account.account_currency self.party_account_currency = account.account_currency
def check_for_closed_status(self): def check_on_hold_or_closed_status(self):
check_list = [] check_list = []
for d in self.get('items'): for d in self.get('items'):
if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt: if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt:
check_list.append(d.purchase_order) check_list.append(d.purchase_order)
check_for_closed_status('Purchase Order', d.purchase_order) check_on_hold_or_closed_status('Purchase Order', d.purchase_order)
def validate_with_previous_doc(self): def validate_with_previous_doc(self):
super(PurchaseInvoice, self).validate_with_previous_doc({ super(PurchaseInvoice, self).validate_with_previous_doc({
@ -760,7 +760,7 @@ class PurchaseInvoice(BuyingController):
def on_cancel(self): def on_cancel(self):
super(PurchaseInvoice, self).on_cancel() super(PurchaseInvoice, self).on_cancel()
self.check_for_closed_status() self.check_on_hold_or_closed_status()
self.update_status_updater_args() self.update_status_updater_args()

View File

@ -36,7 +36,8 @@ frappe.ui.form.on("Purchase Order", {
}, },
refresh: function(frm) { refresh: function(frm) {
if(frm.doc.docstatus == 1 && frm.doc.status == 'To Receive and Bill') { if(frm.doc.docstatus === 1 && frm.doc.status !== 'Closed'
&& flt(frm.doc.per_received) < 100 && flt(frm.doc.per_billed) < 100) {
frm.add_custom_button(__('Update Items'), () => { frm.add_custom_button(__('Update Items'), () => {
erpnext.utils.update_child_items({ erpnext.utils.update_child_items({
frm: frm, frm: frm,
@ -93,62 +94,63 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
} }
} }
cur_frm.set_df_property("drop_ship", "hidden", !is_drop_ship); this.frm.set_df_property("drop_ship", "hidden", !is_drop_ship);
if(doc.docstatus == 1 && !in_list(["Closed", "Delivered"], doc.status)) { if(doc.docstatus == 1) {
if(!in_list(["Closed", "Delivered"], doc.status)) {
if (this.frm.has_perm("submit")) { if (this.frm.has_perm("submit")) {
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) { if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) {
cur_frm.add_custom_button(__('Close'), this.close_purchase_order, __("Status")); if (doc.status != "On Hold") {
this.frm.add_custom_button(__('Hold'), () => this.hold_purchase_order(), __("Status"));
} else{
this.frm.add_custom_button(__('Resume'), () => this.unhold_purchase_order(), __("Status"));
}
this.frm.add_custom_button(__('Close'), () => this.close_purchase_order(), __("Status"));
} }
} }
if(is_drop_ship && doc.status!="Delivered"){ if(is_drop_ship && doc.status!="Delivered") {
cur_frm.add_custom_button(__('Delivered'), this.frm.add_custom_button(__('Delivered'),
this.delivered_by_supplier, __("Status")); this.delivered_by_supplier, __("Status"));
cur_frm.page.set_inner_btn_group_as_primary(__("Status")); this.frm.page.set_inner_btn_group_as_primary(__("Status"));
} }
} else if(doc.docstatus===0) { } else if(in_list(["Closed", "Delivered"], doc.status)) {
cur_frm.cscript.add_from_mappers();
}
if(doc.docstatus == 1 && in_list(["Closed", "Delivered"], doc.status)) {
if (this.frm.has_perm("submit")) { if (this.frm.has_perm("submit")) {
cur_frm.add_custom_button(__('Re-open'), this.unclose_purchase_order, __("Status")); this.frm.add_custom_button(__('Re-open'), () => this.unclose_purchase_order(), __("Status"));
} }
} }
if(doc.status != "Closed") {
if(doc.docstatus == 1 && doc.status != "Closed") { if (doc.status != "On Hold") {
if(flt(doc.per_received, 2) < 100 && allow_receipt) { if(flt(doc.per_received, 2) < 100 && allow_receipt) {
cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create')); cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create'));
if(doc.is_subcontracted==="Yes") { if(doc.is_subcontracted==="Yes") {
cur_frm.add_custom_button(__('Material to Supplier'), cur_frm.add_custom_button(__('Material to Supplier'),
function() { me.make_stock_entry(); }, __("Transfer")); function() { me.make_stock_entry(); }, __("Transfer"));
} }
} }
if(flt(doc.per_billed, 2) < 100) if(flt(doc.per_billed, 2) < 100)
cur_frm.add_custom_button(__('Invoice'), cur_frm.add_custom_button(__('Invoice'),
this.make_purchase_invoice, __('Create')); this.make_purchase_invoice, __('Create'));
if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
}
if(!doc.auto_repeat) { if(!doc.auto_repeat) {
cur_frm.add_custom_button(__('Subscription'), function() { cur_frm.add_custom_button(__('Subscription'), function() {
erpnext.utils.make_subscription(doc.doctype, doc.name) erpnext.utils.make_subscription(doc.doctype, doc.name)
}, __('Create')) }, __('Create'))
} }
}
if(flt(doc.per_billed)==0) { if(flt(doc.per_billed)==0) {
this.frm.add_custom_button(__('Payment Request'), this.frm.add_custom_button(__('Payment Request'),
function() { me.make_payment_request() }, __('Create')); function() { me.make_payment_request() }, __('Create'));
} }
if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
}
cur_frm.page.set_inner_btn_group_as_primary(__('Create')); cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
} }
} else if(doc.docstatus===0) {
cur_frm.cscript.add_from_mappers();
}
}, },
get_items_from_open_material_requests: function() { get_items_from_open_material_requests: function() {
@ -427,6 +429,43 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
} }
}, },
unhold_purchase_order: function(){
cur_frm.cscript.update_status("Resume", "Draft")
},
hold_purchase_order: function(){
var me = this;
var d = new frappe.ui.Dialog({
title: __('Reason for Hold'),
fields: [
{
"fieldname": "reason_for_hold",
"fieldtype": "Text",
"reqd": 1,
}
],
primary_action: function() {
var data = d.get_values();
frappe.call({
method: "frappe.desk.form.utils.add_comment",
args: {
reference_doctype: me.frm.doctype,
reference_name: me.frm.docname,
content: __('Reason for hold: ')+data.reason_for_hold,
comment_email: frappe.session.user
},
callback: function(r) {
if(!r.exc) {
me.update_status('Hold', 'On Hold')
d.hide();
}
}
});
}
});
d.show();
},
unclose_purchase_order: function(){ unclose_purchase_order: function(){
cur_frm.cscript.update_status('Re-open', 'Submitted') cur_frm.cscript.update_status('Re-open', 'Submitted')
}, },

View File

@ -20,6 +20,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "supplier_section", "fieldname": "supplier_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@ -53,6 +54,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "{supplier_name}", "default": "{supplier_name}",
"fetch_if_empty": 0,
"fieldname": "title", "fieldname": "title",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@ -86,6 +88,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "naming_series", "fieldname": "naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@ -121,6 +124,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "supplier", "fieldname": "supplier",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -156,6 +160,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))", "depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))",
"fetch_if_empty": 0,
"fieldname": "get_items_from_open_material_requests", "fieldname": "get_items_from_open_material_requests",
"fieldtype": "Button", "fieldtype": "Button",
"hidden": 0, "hidden": 0,
@ -189,6 +194,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "supplier.supplier_name", "fetch_from": "supplier.supplier_name",
"fetch_if_empty": 0,
"fieldname": "supplier_name", "fieldname": "supplier_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@ -222,6 +228,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "company", "fieldname": "company",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -256,6 +263,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break1", "fieldname": "column_break1",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@ -3310,7 +3318,7 @@
"no_copy": 1, "no_copy": 1,
"oldfieldname": "status", "oldfieldname": "status",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nDraft\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nCancelled\nClosed\nDelivered", "options": "\nDraft\nOn Hold\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nCancelled\nClosed\nDelivered",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
@ -3531,6 +3539,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "letter_head", "fieldname": "letter_head",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -3565,6 +3574,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "select_print_heading", "fieldname": "select_print_heading",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -3599,6 +3609,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_86", "fieldname": "column_break_86",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@ -3631,6 +3642,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "group_same_items", "fieldname": "group_same_items",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@ -3664,6 +3676,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "language", "fieldname": "language",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@ -3697,6 +3710,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "subscription_section", "fieldname": "subscription_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@ -3731,6 +3745,7 @@
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "from_date", "fieldname": "from_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@ -3764,6 +3779,7 @@
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "to_date", "fieldname": "to_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@ -3795,6 +3811,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_97", "fieldname": "column_break_97",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@ -3826,6 +3843,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "auto_repeat", "fieldname": "auto_repeat",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@ -3860,6 +3878,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval: doc.auto_repeat", "depends_on": "eval: doc.auto_repeat",
"fetch_if_empty": 0,
"fieldname": "update_auto_repeat_reference", "fieldname": "update_auto_repeat_reference",
"fieldtype": "Button", "fieldtype": "Button",
"hidden": 0, "hidden": 0,

View File

@ -11,7 +11,7 @@ from erpnext.controllers.buying_controller import BuyingController
from erpnext.stock.doctype.item.item import get_last_purchase_details from erpnext.stock.doctype.item.item import get_last_purchase_details
from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty 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_on_hold_or_closed_status
from erpnext.stock.utils import get_bin from erpnext.stock.utils import get_bin
from erpnext.accounts.party import get_party_account_currency from erpnext.accounts.party import get_party_account_currency
from six import string_types from six import string_types
@ -45,7 +45,7 @@ class PurchaseOrder(BuyingController):
self.validate_supplier() self.validate_supplier()
self.validate_schedule_date() self.validate_schedule_date()
validate_for_items(self) validate_for_items(self)
self.check_for_closed_status() self.check_on_hold_or_closed_status()
self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("uom", "qty")
self.validate_uom_is_integer("stock_uom", "stock_qty") self.validate_uom_is_integer("stock_uom", "stock_qty")
@ -144,12 +144,12 @@ class PurchaseOrder(BuyingController):
= d.rate = d.last_purchase_rate = item_last_purchase_rate = d.rate = d.last_purchase_rate = item_last_purchase_rate
# Check for Closed status # Check for Closed status
def check_for_closed_status(self): def check_on_hold_or_closed_status(self):
check_list =[] check_list =[]
for d in self.get('items'): for d in self.get('items'):
if d.meta.get_field('material_request') and d.material_request and d.material_request not in check_list: if d.meta.get_field('material_request') and d.material_request and d.material_request not in check_list:
check_list.append(d.material_request) check_list.append(d.material_request)
check_for_closed_status('Material Request', d.material_request) check_on_hold_or_closed_status('Material Request', d.material_request)
def update_requested_qty(self): def update_requested_qty(self):
material_request_map = {} material_request_map = {}
@ -232,7 +232,7 @@ class PurchaseOrder(BuyingController):
if self.is_subcontracted == "Yes": if self.is_subcontracted == "Yes":
self.update_reserved_qty_for_subcontract() self.update_reserved_qty_for_subcontract()
self.check_for_closed_status() self.check_on_hold_or_closed_status()
frappe.db.set(self,'status','Cancelled') frappe.db.set(self,'status','Cancelled')

View File

@ -4,6 +4,8 @@ frappe.listview_settings['Purchase Order'] = {
get_indicator: function (doc) { get_indicator: function (doc) {
if (doc.status === "Closed") { if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"]; return [__("Closed"), "green", "status,=,Closed"];
} else if (doc.status === "On Hold") {
return [__("On Hold"), "orange", "status,=,On Hold"];
} else if (doc.status === "Delivered") { } else if (doc.status === "Delivered") {
return [__("Delivered"), "green", "status,=,Closed"]; return [__("Delivered"), "green", "status,=,Closed"];
} else if (flt(doc.per_received, 2) < 100 && doc.status !== "Closed") { } else if (flt(doc.per_received, 2) < 100 && doc.status !== "Closed") {

View File

@ -120,6 +120,15 @@ class TestPurchaseOrder(unittest.TestCase):
self.assertEqual(pi.doctype, "Purchase Invoice") self.assertEqual(pi.doctype, "Purchase Invoice")
self.assertEqual(len(pi.get("items", [])), 1) self.assertEqual(len(pi.get("items", [])), 1)
def test_purchase_order_on_hold(self):
po = create_purchase_order(item_code="_Test Product Bundle Item")
po.db_set('Status', "On Hold")
pi = make_purchase_invoice(po.name)
pr = make_purchase_receipt(po.name)
self.assertRaises(frappe.ValidationError, pr.submit)
self.assertRaises(frappe.ValidationError, pi.submit)
def test_make_purchase_invoice_with_terms(self): def test_make_purchase_invoice_with_terms(self):
po = create_purchase_order(do_not_save=True) po = create_purchase_order(do_not_save=True)

View File

@ -73,10 +73,10 @@ def validate_for_items(doc):
not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0): not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0):
frappe.throw(_("Same item cannot be entered multiple times.")) frappe.throw(_("Same item cannot be entered multiple times."))
def check_for_closed_status(doctype, docname): def check_on_hold_or_closed_status(doctype, docname):
status = frappe.db.get_value(doctype, docname, "status") status = frappe.db.get_value(doctype, docname, "status")
if status == "Closed": if status in ("Closed", "On Hold"):
frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError) frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError)
@frappe.whitelist() @frappe.whitelist()

View File

@ -70,6 +70,7 @@ status_map = {
["Completed", "eval:self.per_received == 100 and self.per_billed == 100 and self.docstatus == 1"], ["Completed", "eval:self.per_received == 100 and self.per_billed == 100 and self.docstatus == 1"],
["Delivered", "eval:self.status=='Delivered'"], ["Delivered", "eval:self.status=='Delivered'"],
["Cancelled", "eval:self.docstatus==2"], ["Cancelled", "eval:self.docstatus==2"],
["On Hold", "eval:self.status=='On Hold'"],
["Closed", "eval:self.status=='Closed'"], ["Closed", "eval:self.status=='Closed'"],
], ],
"Delivery Note": [ "Delivery Note": [

View File

@ -13,7 +13,7 @@ from frappe.model.mapper import get_mapped_doc
from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
from erpnext.controllers.buying_controller import BuyingController from erpnext.controllers.buying_controller import BuyingController
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
from erpnext.buying.utils import check_for_closed_status, validate_for_items from erpnext.buying.utils import check_on_hold_or_closed_status, validate_for_items
from erpnext.stock.doctype.item.item import get_item_defaults from erpnext.stock.doctype.item.item import get_item_defaults
from six import string_types from six import string_types
@ -100,7 +100,7 @@ class MaterialRequest(BuyingController):
def before_cancel(self): def before_cancel(self):
# if MRQ is already closed, no point saving the document # if MRQ is already closed, no point saving the document
check_for_closed_status(self.doctype, self.name) check_on_hold_or_closed_status(self.doctype, self.name)
self.set_status(update=True, status='Cancelled') self.set_status(update=True, status='Cancelled')
def check_modified_date(self): def check_modified_date(self):

View File

@ -88,7 +88,7 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
}, },
get_query_filters: { get_query_filters: {
docstatus: 1, docstatus: 1,
status: ["!=", "Closed"], status: ["not in", ["Closed", "On Hold"]],
per_received: ["<", 99.99], per_received: ["<", 99.99],
company: me.frm.doc.company company: me.frm.doc.company
} }

View File

@ -12,7 +12,7 @@ from frappe.utils import getdate
from erpnext.controllers.buying_controller import BuyingController from erpnext.controllers.buying_controller import BuyingController
from erpnext.accounts.utils import get_account_currency from erpnext.accounts.utils import get_account_currency
from frappe.desk.notifications import clear_doctype_notifications from frappe.desk.notifications import clear_doctype_notifications
from erpnext.buying.utils import check_for_closed_status from erpnext.buying.utils import check_on_hold_or_closed_status
from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled
from six import iteritems from six import iteritems
@ -62,7 +62,7 @@ class PurchaseReceipt(BuyingController):
self.validate_uom_is_integer("uom", ["qty", "received_qty"]) self.validate_uom_is_integer("uom", ["qty", "received_qty"])
self.validate_uom_is_integer("stock_uom", "stock_qty") self.validate_uom_is_integer("stock_uom", "stock_qty")
self.check_for_closed_status() self.check_on_hold_or_closed_status()
if getdate(self.posting_date) > getdate(nowdate()): if getdate(self.posting_date) > getdate(nowdate()):
throw(_("Posting Date cannot be future date")) throw(_("Posting Date cannot be future date"))
@ -103,13 +103,13 @@ class PurchaseReceipt(BuyingController):
return po_qty, po_warehouse return po_qty, po_warehouse
# Check for Closed status # Check for Closed status
def check_for_closed_status(self): def check_on_hold_or_closed_status(self):
check_list =[] check_list =[]
for d in self.get('items'): for d in self.get('items'):
if (d.meta.get_field('purchase_order') and d.purchase_order if (d.meta.get_field('purchase_order') and d.purchase_order
and d.purchase_order not in check_list): and d.purchase_order not in check_list):
check_list.append(d.purchase_order) check_list.append(d.purchase_order)
check_for_closed_status('Purchase Order', d.purchase_order) check_on_hold_or_closed_status('Purchase Order', d.purchase_order)
# on submit # on submit
def on_submit(self): def on_submit(self):
@ -147,7 +147,7 @@ class PurchaseReceipt(BuyingController):
def on_cancel(self): def on_cancel(self):
super(PurchaseReceipt, self).on_cancel() super(PurchaseReceipt, self).on_cancel()
self.check_for_closed_status() self.check_on_hold_or_closed_status()
# Check if Purchase Invoice has been submitted against current Purchase Order # Check if Purchase Invoice has been submitted against current Purchase Order
submitted = frappe.db.sql("""select t1.name submitted = frappe.db.sql("""select t1.name
from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2